目录
完整代码在最下面
结构体和头文件
#include<stdio.h>
#include<stdlib.h>
typedef struct linklist
{
int data;//数据域
struct linklist* next;指针域
}linklist;
全局声明
linklist* head;
建表函数
尾插法演示:
linklist* createlist(int i)//传递参数i,i是链表长度
{
linklist* p;
linklist* r;
linklist* head;
head = (linklist*)malloc(sizeof(linklist));//开辟头节点
head->next = NULL;//将头节点的next指向null
r = (linklist*)malloc(sizeof(linklist));//开辟r结点
head = r;//把r结点等于头节点
int n;
printf("请输入数字:");
for (n = 0; n < i; n++)
{
p = (linklist*)malloc(sizeof(linklist));//注意循环开辟p结点
scanf("%d", &p->data);//给p结点的data赋值
r->next = p;//将r的next指向p
r = p;//r结点等于p结点
}
r->next = NULL;//r的next指向null
printf("创建链表成功\n");
return head;返回头节点
}
linklist* createlist(int i),int(i)最后解释。
尾插法的要点在于在头节点后面开辟结点,然后连接上一个结点,字面上理解很抽象,我画了一幅图,简化为以下五步。有点丑,不要介意。
第一步:开辟了头节点。
第二步:r结点等于头节点,也就是让r指向head的数据域和指针域。
第三步:第三步开辟了p结点,并把3赋值给p的数据域。
第四步:把新开辟的p结点连上头节点,也就是r->next = p;(注意此时r=head)。
第五步:把r结点等于p结点。
④⑤是尾插法的精髓,创建很多结点再把他们头尾相连形成链表,就在于不断开辟新的p结点,给他们的数据域赋值,然后与上一个r结点相连接,最后把r结点等于新开辟的p结点。这也就是为什么要把以下四步放入循环中。
p = (linklist*)malloc(sizeof(linklist));
scanf("%d", &p->data);
r->next = p;
r = p;
如果再开辟一个新的p结点,操作如下:
最后不要忘记把head的null赋给移动到最后的r结点。
int i;是主函数传递的实际参数给建表函数,以下是主函数里的建表函数。
主函数里给i赋值,然后把i传递给建表函数,当然也可以把printf和scanf两句放到建表函数里。
插入函数
linklist* insertlist(linklist* head, int a, int e, int i)//传递参数,a是插入位置,e是需要插入的数值,i是链表长度
{
linklist* s = (linklist*)malloc(sizeof(linklist));//开辟s结点
linklist* p = head;//p结点等于头节点
s->next = NULL;//s的next指向null
s->data = e;//将s的data赋值给e
int j = 0;
if (a >= i || a < 0)//如果插入的位置小于0或大于链表长度,则输入位置有误
{
printf("插入位置输入错误!\n");
exit(1);
}
while (p != NULL)//见详解
{
if (j == a)
{
s->next = p->next;
p->next = s;
}
p = p->next;
j++;
}
i++;
printf("%d在第%d号位插入成功!\n", e, a);
return head;
}
插入的要点在于将新开辟的s结点的data赋值,然后先与后一个结点相连,再与上一个结点相连,如图:
如果①②对换顺序,先p->next = s;再s->next = p->next;此时p的next已经等于了s,再到s->next = p->next;时,就变成了s->next = s;,所以①②的顺序不能对换。
主函数里的插入函数:
linklist* p = head;
因为while循环里p = p->next;遍历结点,所以要把p赋给头结点。
int j=0;
什么时候插入s结点,需要一个计数器,j就充当了这个位置,当输入的位置a与j相等时,说明就在此时进入if语句并插入s结点。
删除函数
linklist* detellist(linklist* head, int a, int i)//a是删除的位置,i是链表长度
{
linklist* p = head;
linklist* q = (linklist*)malloc(sizeof(linklist));//开辟q结点
int j = 0;
if (a > i || a < 0)
{
printf("删除位置输入错误!\n");//如果插入的位置小于0或大于链表长度,则输入位置有误
exit(1);
}
while (p != NULL)
{
if (j == a)
{
q = p->next;
p->next = q->next;
}
p = p->next;
j++;
}
printf("%d删除成功\n", q->data);
free(q);//释放q结点
return head;
}
当j==a,也就是输入的位置与需要删除的位置相等时,进入if语句,q等于p的下一个结点,也就是需要删除的结点,先把p与q的下一个结点相连,再释放q结点,如果先释放q结点,会导致断链。
举个例子更好理解:
比如我需要删除2(2的位置为1),输入a=1,第一次循环p=head,j=0,a=1,不进入if语句;程序走过p=p->next,j++后,此时进入第二次循环,j==a==1,进入if语句q = p->next,q就指向了2所在结点,p再绕过q连接下一个结点,随后释放p结点。代码里之所以没有写为
while (p != NULL)
{
if (j == a)
{
q = p->next;
p->next = q->next;
free(q);
}
p = p->next;
j++;
}
是因为printf("%d删除成功\n", q->data);中用到了q。
操作如图:
查找函数
linklist* searchlist(linklist* head,int e)
{
linklist* p;
p = head->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
if (p->data == e)
printf("%d的地址为:%p", e, p);
else
{
printf("查找数值输入错误!");
exit(1);
}
return head;
}
查找比较简单,让p遍历链表,输出与e相等的p->data的p的地址。注意p=head->next,因为head始终是空的,还有while里的循环条件。
取值函数
linklist* getlist(int i, int a)//i是链表长度,a是需要取值的位置
{
linklist* p;
int e;
p = head->next;
int j = 0;
if (a >= i || a < 0)//如果插入的位置小于0或大于链表长度,则输入位置有误
{
printf("取值位置输入错误!\n");
exit(1);
}
while (p != NULL && a != j )
{
p = p->next;
j++;
}
if (a == j)
printf("%d号位是%d", a, p->data);
return head;
}
要输出序号,就需要一个计数器,这里j充当计数器,当j与需要取值的位置a相等时,输出此时p的data即可。注意如果输入的是1 2 3,实际上的位置是0 1 2。 同样需要注意while里的条件。
输出函数
linklist* inputlist(linklist* head)
{
linklist* p = head;
p = head->next;
printf("顺序表里的元素有:\n");
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
return head;
}
p遍历链表并输出p的data,注意p = head->next。
退出函数
linklist* outlist(linklist* head)
{
linklist* p = head;
linklist* d;
p = head->next;
while (p != NULL)
{
linklist* d = (linklist*)malloc(sizeof(linklist));
d = p;
p = p->next;
free(d);
}
printf("退出成功!");
return head;
}
操作如图:
因为d最后要被释放,所以开辟d放入循环里,每次重新开辟。
菜单函数
void menu()
{
printf("\n****************************************************************\n");
printf("\n*********** 请输入你的选择 ***********\n");
printf("\n*********** 1 ---- 建表 ***********\n");
printf("\n*********** 2 ---- 插入 ***********\n");
printf("\n*********** 3 ---- 删除 ***********\n");
printf("\n*********** 4 ---- 查找 ***********\n");
printf("\n*********** 5 ---- 取值 ***********\n");
printf("\n*********** 6 ---- 输出链表 ***********\n");
printf("\n*********** 0 ---- 退出 ***********\n");
printf("\n****************************************************************\n");
}
主函数
int main()
{
int i, a, e;
while (1)
{
menu();
int choice;
printf("请选择功能:");
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("请输入创建的链表的长度:");
scanf("%d", &i);
head = createlist(i);
break;
case 2:
printf("请输入需要插入的位置:");
scanf("%d", &a);
printf("请输入需要插入的数字:");
scanf("%d", &e);
insertlist(head, a, e, i);
break;
case 3:
printf("请输入需要删除的位置:");
scanf("%d", &a);
detellist(head, a, i);
break;
case 4:
printf("请输入需要查找地址的数:");
scanf("%d", &e);
searchlist(head, e);
break;
case 5:
printf("请输入需要取值的位置:");
scanf("%d", &a);
getlist(i, a);
break;
case 6:
inputlist(head);
break;
case 0:
outlist(head);
break;
}
}
return 0;
}
完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
typedef struct linklist
{
int data;
struct linklist* next;
}linklist;
linklist* head;
void menu()
{
printf("\n****************************************************************\n");
printf("\n*********** 请输入你的选择 ***********\n");
printf("\n*********** 1 ---- 建表 ***********\n");
printf("\n*********** 2 ---- 插入 ***********\n");
printf("\n*********** 3 ---- 删除 ***********\n");
printf("\n*********** 4 ---- 查找 ***********\n");
printf("\n*********** 5 ---- 取值 ***********\n");
printf("\n*********** 6 ---- 输出链表 ***********\n");
printf("\n*********** 0 ---- 退出 ***********\n");
printf("\n****************************************************************\n");
}
linklist* createlist(int i)
{
linklist* p;
linklist* r;
linklist* head;
head = (linklist*)malloc(sizeof(linklist));
head->next = NULL;
r = (linklist*)malloc(sizeof(linklist));
r = head;
int n;
printf("请输入数字:");
for (n = 0; n < i; n++)
{
p = (linklist*)malloc(sizeof(linklist));
scanf("%d", &p->data);
r->next = p;
r = p;
}
r->next = NULL;
printf("创建链表成功\n");
return head;
}
linklist* insertlist(linklist* head, int a, int e, int i)
{
linklist* s = (linklist*)malloc(sizeof(linklist));
linklist* p = head;
s->next = NULL;
s->data = e;
int j = 0;
if (a >= i || a < 0)
{
printf("插入位置输入错误!\n");
exit(1);
}
while (p != NULL)
{
if (j == a)
{
s->next = p->next;
p->next = s;
}
p = p->next;
j++;
}
printf("%d在第%d号位插入成功!\n", e, a);
return head;
}
linklist* detellist(linklist* head, int a, int i)
{
linklist* p = head;
linklist* q = (linklist*)malloc(sizeof(linklist));
int j = 0;
if (a >= i || a < 0)
{
printf("删除位置输入错误!\n");
exit(1);
}
while (p != NULL)
{
if (j == a)
{
q = p->next;
p->next = q->next;
}
p = p->next;
j++;
}
printf("%d删除成功\n", q->data);
free(q);
return head;
}
linklist* searchlist(linklist* head,int e)
{
linklist* p;
p = head->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
if (p->data == e)
printf("%d的地址为:%p", e, p);
else
{
printf("查找数值输入错误!");
exit(1);
}
return head;
}
linklist* getlist(int i, int a)
{
linklist* p;
p = head->next;
int j = 0;
if (a >= i || a < 0)
{
printf("取值位置输入错误!\n");
exit(1);
}
while (p != NULL && a != j )
{
p = p->next;
j++;
}
if (a == j)
printf("%d号位是%d", a, p->data);
return head;
}
linklist* inputlist(linklist* head)
{
linklist* p = head;
p = head->next;
printf("顺序表里的元素有:\n");
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
return head;
}
linklist* outlist(linklist* head)
{
linklist* p = head;
linklist* d;
p = head->next;
while (p != NULL)
{
linklist* d = (linklist*)malloc(sizeof(linklist));
d = p;
p = p->next;
free(d);
}
printf("退出成功!");
return head;
}
int main()
{
int i, a, e;
while (1)
{
menu();
int choice;
printf("请选择功能:");
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("请输入创建的链表的长度:");
scanf("%d", &i);
head = createlist(i);
break;
case 2:
printf("请输入需要插入的位置:");
scanf("%d", &a);
printf("请输入需要插入的数字:");
scanf("%d", &e);
insertlist(head, a, e, i);
break;
case 3:
printf("请输入需要删除的位置:");
scanf("%d", &a);
detellist(head, a, i);
break;
case 4:
printf("请输入需要查找地址的数:");
scanf("%d", &e);
searchlist(head, e);
break;
case 5:
printf("请输入需要取值的位置:");
scanf("%d", &a);
getlist(i, a);
break;
case 6:
inputlist(head);
break;
case 0:
outlist(head);
break;
}
}
return 0;
}