单链表:

一种逻辑连续但物理地址不一定连续的线性存储结构;
多多读读书上的对单链表的文字性描述;

typedef int DataType;
typedef struct linkList{
DataType data; //数据域
struct linkList* next; //指针域

}LinkList,*List;

包括data数据域和next指针域;
List 相当于 struct linkList * ,指针类型;
看个人喜好编辑指针!!!
链表也分带头结点的链表和不带头结点的链表;
通常用一个“头指针”来表示一个线性链表;

1、初始化链表

  • 其实就是为了给头结点申请个开始地址!!!
List LinitList(){/*初始化链表函数,设置一个头指针,并将链表设置为空*/ 
LinkList *L;
L = (List)malloc(sizeof(LinkList));//建立头结点
L->next = NULL;//置单链表L为空
return L;
}

用法就是:定义一个头指针,返回出其申请的地址

List head; // 链表指针结点(是指针变量哦,后面就不在多说了)
/*上面一句也可写成 LinkList *head ;*/
head = LinitList();

2、单链表的建立

  • 头插法

/头插法,建立线性链表从空表开始,每读入一个有效数据就要申请结点s,并将新的结点链接在头结点之后,所以会倒序输出/

  • 算法思想:首先要申请一个地址空间(指针),然后给这个结点(指针)的数值域赋值, 然后再给这个结点的指针域将头结点的指针域给其赋值,然后将申请的新结点给赋值给头结点上的指针域(也就是指针指向),依次类推;
void CreateList(List head,int n){
/*头插List head == LinkList* head*/

List s;//储存新结点
int i;
printf("请输入%d个数字",n);
for(i=0;i<n;i++){
s = (List)malloc(sizeof(LinkList));//创建新的 结点地址
scanf("%d",&s->data); //给 此结点的数值域赋值
s->next = head->next; //即 将新的结点化为头结点
head->next = s; //将 新节点插入在头结点之后
}
printf("建立链表操作成功\n");
}
  • 需要注意的是下面这两个核心语句的顺序不能颠倒
s->next = head->next;  
head->next = s;
  • 尾插法
  • 算法思想:首先理解,我输入的S结点的尾指针变量是需要设置为空NULL,给这个指针变量的指针域赋值其新申请的S地址再让这个尾指针永远指向最后一个结点,依次循环。(实在理解不了就需要背咯)
void CreateListL(List head,int n){
/*尾插法建立链表函数*/
List s,last;
int i;
last = head;
printf("请输入%d个数字",n);
for(i=0;i<n;i++){
s = (List)malloc(sizeof(LinkList));//创建新的 结点地址
scanf("%d",&s->data); //给 此结点的数值域赋值
s->next = NULL; //即 将新的结点指针域为空
last->next = s; //将 新节点插入在头结点之后
last = s;
}
printf("建立链表操作成功\n");
}

3、链表的输出

算法思想:在这个单链表中最后的一个结点的指针域是NULL的,那么从知道链表的第一个结点开始,通过检索指向下一个结点的指针域从而访问下一个结点的数值域。

void DisPlay(list head){
list s = head->next;
while(s != NULL){
printf("%d\t",s->data);
s = s->next;//指向下一个结点
}
printf("\n");
}

4、求表长操作

int LengthList(list head){
list s = head->next;
int len = 0;
while(s != NULL){
s = s->next;
len++;
}
return len;
}

5、查找操作

  • 按值查找:从链表的第一个元素结点开始依次对比各个数据域,若与需找相等的则循环结束,否则继续比较直到结束,还得判断其指针域不能为空。
  • 求链表的长度函数
int LengthList(list head){
list s = head->next;
int len = 0;
while(s != NULL){
s = s->next;
len++;
}
return len;
}
void Locate(list head,DataType x){
list s = head->next;
int i=1;
while(s->data != x && s->next != NULL){
s = s->next;
i++;
}
if(s!=NULL){
printf("在链表的第%d位找到值为%d的结点\n",i,x);
}else{
printf("未找到值为%d的结点\n");
}
}

思考:
根据上段代码风格,为什么此处的 i 要赋值为1呢?
(提示:结合限制条件 + while语法规则)

  • 按序号查找
void SearchList(list head,int i){
list s = head;
int j=0;
if(i > LengthList(head)){
printf("查找位置已超出链表长度最大值\n");
}
while(s->next != NULL && j<i){
s = s->next;
j++;
}
if(j==i){
printf("在链表的第%d位找到值为%d的结点\n",i,s->data);
}
}

(注意此处的 LengthList(head) 表示单链表的长度)

6、插入操作

(只在链表内部插入)

void InsList(list head,int i,DataType x){
list p,s;
int j=0;
p = head;
while(p->next != NULL && j<i-1){//只能在链表内插入
p = p->next; //找到这个需要插入的结点位置p
j++;
}
if(p != NULL){
s = (list)malloc(sizeof(LinkList));
s->data = x;
s->next = p->next;
p->next = s;
printf("掺入元素成功\n");
}else{
printf("插入元素失败\n");
}
}

7、删除操作

void DelList(list head,int i){
/*按位置删除链表中元素位置*/
list p,s;
int j=0;
DataType x;
p = head;
while(p->next != NULL && j<i-1){//只能在链表内插入
p = p->next; //找到这个需要插入的结点位置p
j++;
}
if(p->next != NULL && j==i-1){
s = p->next;
x = s->data;
p->next = s->next;
free(s);
printf("删除第%d位上的元素%d成功\n",i,x);
}else{
printf("删除结点位置错误,删除失败\n");
}
}

8、菜单

void Menu(){
printf("\t\t顺序表的各种操作\n");
printf("======================================\n");
printf("\t1——建立\n");
printf("\t2——插入\n");
printf("\t3——删除\n");
printf("\t4——按位置查找\n");
printf("\t5——按元素值查找\n");
printf("\t6——求链表的长度 \n");
printf("\t0——返回\n");
printf("======================================\n");
printf("请输入菜单号(0-6):\n");
}

9、完整的操作代码如下:

void Menu(){
printf("\t\t顺序表的各种操作\n");
printf("======================================\n");
printf("\t1——建立\n");
printf("\t2——插入\n");
printf("\t3——删除\n");
printf("\t4——按位置查找\n");
printf("\t5——按元素值查找\n");
printf("\t6——求链表的长度 \n");
printf("\t0——返回\n");
printf("======================================\n");
printf("请输入菜单号(0-6):\n");
}
int main() {
list head;
char ch1='y',ch2,b;
DataType x;
int n,i;
while(ch1 == 'y'||ch1 == 'Y'){
Menu();
scanf("%c",&ch2);
getchar();
switch(ch2){
case '1':
head = InitList();
printf("请输入需要建立线性表的长度:");
scanf("%d",&n);
CreatListL(head,n);
printf("建立后的线性表为:");
DisPlay(head);
break;
case '2':
printf("请输入要插入元素的位置:");
scanf("%d",&n);
printf("请输入要插入的元素值:");
scanf("%d",&i);
InsList(head,n,i);
printf("插入后的链表为:");
DisPlay(head);
break;
case '3':
printf("请输入要删除元素的位置:");
scanf("%d",&i);
DelList(head,i);
printf("删除后的链表为:");
DisPlay(head);
break;
case '4':
printf("请输入要查找元素的位置:");
scanf("%d",&i);
SearchList(head,i);
break;
case '5':
printf("请输入要查找的整数:");
scanf("%d",&n);
Locate(head,n);
break;
case '6':
printf("线性表的长度为:%d",LengthList(head));
case '0':
ch1 = 'n';
printf("已退出程序!!!");
break;
default :
printf("输入有误,请按0-6进行选择!\n");

}
if(ch2 != '0'){
// getchar();
// printf("\n按r/R键结束,按任意键返回主菜单!\n");
// scanf("%c",&b);
// if(b == 'R'||b== 'r'){
// ch1 = 'n';
// }
getchar();
printf("\n按回车键继续/结束,按任意键返回主菜单!\n");
scanf("%c",&b);
getchar();
if(b == '\xA'){
ch1 = 'n';
}
}
}
return 0;
}