c语言数据结构:单链表
咳咳,话不多说,上代码!
#include <stdio.h>
#include <stdlib.h> //此头文件包函malloc动态申请内存函数
//创建一个名为list的结构体
typedef struct list
{
//结构体数据,你想多整几个也行,我在这只放了一个,不是我想偷懒啊
int data;
//弄一个指向下一个结点的结构体的尾指针
struct list* next;
}L; //用typedef让L来代替struct list,节约点按键盘次数
//创建链表
//L* 为此函数的类型为L*也就是struct list*,返回结构体函数指针
L* creatorList()
{
//定义一个结构体指针并分配内存空间,分配大小为此结构体所占内存大小
L* headlist = (L*)malloc(sizeof(L));
//表头只是起到一个引导作用,所以不用给其赋值
//刚创建的链表为空,所以需要让表头的尾结点指向NULL
headlist->next = NULL;
//返回创建好的链表
return headlist;
}
话不多说,上代码!
//创建结点
L* creatorNode(int data)
{
//跟之前创建链表的时候相同,结点也需要申请内存空间
L* newNode = (L*)malloc(sizeof(L));
//不过,之前创建的链表只有表头,只起到了引导作用
//所以,结点里面就可以放数据了
newNode->data = data;
//将结点的尾指针指向NULL
newNode->next = NULL;
//返回结点
return newNode;
}
头插法:
//函数参数为要插入的链表和要插入其中的结点
void insertNode(L* head,L* newNode)
{
//首先先让新结点的尾指针指向头结点所指的结点
newNode->next = head->next;
//再让头结点指向新结点
head->next = newNode;
}
尾插法:
void insertNode(L* head,L* newNode)
{
//首先再定义一个指针指向链表的头结点
L* pMove = head; //此做法是让head一直是链表头结点
while(pMove->next!=NULL) //判断pMove是否移动到了链表的最后一个结点
pMove = pMove->next; //使pMove移动至下一个节点
//循环完毕之后表示pMove已经指向了链表的最后一个结点
pMove->next = newNode; //将pMove,即尾结点的尾指针指向新结点
}
排序插法:
void insertNode(L* head,L* newNode)
{
L* pMove = head; //此做法是让head一直是链表头结点
//判断pMove是否移动到了尾结点
while(pMove->next!=NULL)
{
//判断pMove所指结点的数据的数是否小于新结点的数据,然后再判
//断pMove所指结点的尾指针所指的结点的数据是否大于新结点数据
if(pMove->data<newNode->data&&pMove->next->data>newNode->data)
{
//条件成立,此下操作就跟头插法差不多
//让新结点的尾指针指向pMove所指结点的尾指针所指的结点
newNode->next = pMove->next;
//让pMove所指结点的尾指针指向新结点
pMove->next = newNode;
//插入完成,return返回
return;
}
//让pMove指向下一个结点
pMove = pMove->next;
}
//循环完毕后,此时pMove为链表尾结点,让pMove所指结点的尾指针指向新结点
pMove->next = newNode;
}
上代码!!!
void queryNode(L* head,int data)
{
//定义一个整形i的目的是显示其所查询的数据在第几个结点
int i=1;
L* pMove = head->next;
while(pMove)
{
//判断数据是否匹配
if(pMove->data==data)
{
//输出查找到的结点数据和它所在结点位置
printf("已找到数据:%d,它在第%d结点",pMove->data,i);
//已查找到,return返回,不让继续执行下面程序
return;
}
i++;
pMove = pMove->next;
}
//循环结束表示没有找到
printf("未找到匹配数据\n");
}
上代码!!!
void changeNode(L* head,int data)
{
L* pMove = head->next;
while(pMove)
{
//如果数据匹配
if(pMove->data==data)
{
printf("请输入修改后的数据:");
scanf("%d",&data);
//将此结点数据修改
pMove->data = data;
printf("修改完成!\n");
return;
}
pMove = pMove->next;
}
//循环结束表示没有找到匹配结点
printf("未找到匹配结点\n");
}
void deteleNode(L* head,int data)
{
L* pMove = head;
//定义一个结构体指针,指向pMove所指结点的下一个节点
L* dpMove = pMove->next;
while(dpMove)
{
//如果结点数据匹配
if(dpMove->data==data)
{
//这里的操作就跟头插入差不多
//让pMove所指结点的尾指针指向dpMove所指结点的尾指针所指的结点
pMove->next = dpMove->next;
//释放dpMove所指的结点内存
free(dpMove);
printf("删除完成!\n");
return;
}
pMove = pMove->next;
dpMove = pMove->next;
}
//循环结束表示没有找到匹配结点
printf("未找到匹配结点\n");
}
void printlist(L* head)
{
//让PMove指向头结点的下一个结点
L* pMove = head->next;
//如果PMove所指结点为NULL,则表示其链表为空
if(pMove==NULL)
{
printf("链表为空\n");
return;
}
//这里的头是表示头结点,它起一个引导作用
printf("头");
//当pMove不为NULL,同不为0时
while(pMove)
{
//输出结点数据
printf("->%d",pMove->data);
//让pMove指向下一个结点
pMove = pMove->next;
}
//结点输出完输出NULL的意义为,能更直观的看到链表的结构
printf("->NULL\n");
}
哼哼,年轻人,我只想说,你只是数据比较少而已,如果非常多的话,你的电脑非得卡死崩了不成,首先要知道啊,我们的运行内存分为代码区、全局区、栈区、堆区这四大区,代码区用来存放加载你所写的代码,全局区也称静态区,用来存放全局变量和静态变量,栈区用来存放局部变量,堆区就是malloc开辟内存的区域,前三区开辟的内存空间它们很懂事,知道自己收拾自己的烂摊子(自动释放内存),而堆区不一样,需要你自己手动去释放,如果你不去自己释放的话,它就会一直在那里,直到你电脑重启为止,这种类似的事件就比如:你手机或电脑突然卡得很,然后你重启一下,就又好了。
OK,上代码!!!
尾删法:
void detelelist(L* head)
{
L* pMove;
L* detele;
while(1)
{
pMove = head;
//如果下面的条件成立,表示链表为空,跳出循环
if(pMove->next==NULL)
break;
//判断pMove所指结点的尾指针所指的尾指针所指的结点是否为NULL
//此做法是为了给detele留个位位好释放它所指的尾结点
while(pMove->next->next!=NULL)
pMove = pMove->next;
//此时pMove所指的结点的尾指针所指的结点为尾结点
//让detele指向它!!!
detele = pMove->next;
//让pMove所指的结点的尾结点指向detele所指结点的尾指针所指,即NULL
pMove->next = detele->next;
//释放它!!!
free(detele);
//每释放一次输出一次链表
printlist(head);
}
//此时链表为空,将头结点指针置为NULL
head = NULL;
}
头删法:
void detelelist(L* head)
{
L* pMove = head->next;
while(pMove)
{
//让头结点的尾指针指向pMove所指结点的尾指针所指的结点
head->next = pMove->next;
//釈放する!!(释放它!!)
free(pMove);
//让pMove指向下一个结点
pMove = head->next;
//每释放一个结点输出一次链表
printlist(head);
}
//此时链表为空,将头结点指针置为NULL
head = NULL;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct list
{
int data;
struct list* next;
}L;
L* creatorList()
{
L* headlist = (L*)malloc(sizeof(L));
headlist->next = NULL;
return headlist;
}
L* creatorNode(int data)
{
L* newNode = (L*)malloc(sizeof(L));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
void insertNode(L* head,L* newNode)
{
L* pMove = head;
while(pMove->next!=NULL)
{
if(pMove->data<newNode->data&&pMove->next->data>newNode->data)
{
newNode->next = pMove->next;
pMove->next = newNode;
return;
}
pMove = pMove->next;
}
pMove->next = newNode;
}
void queryNode(L* head,int data)
{
int i=1;
L* pMove = head->next;
while(pMove)
{
if(pMove->data==data)
{
printf("已找到数据:%d,它在第%d结点",pMove->data,i);
return;
}
i++;
pMove = pMove->next;
}
printf("未找到匹配数据\n");
}
void changeNode(L* head,int data)
{
L* pMove = head->next;
while(pMove)
{
if(pMove->data==data)
{
printf("请输入修改后的数据:");
scanf("%d",&data);
pMove->data = data;
printf("修改完成!\n");
return;
}
pMove = pMove->next;
}
printf("未找到匹配结点\n");
}
void deteleNode(L* head,int data)
{
L* pMove = head;
L* dpMove = pMove->next;
while(dpMove)
{
if(dpMove->data==data)
{
pMove->next = dpMove->next;
free(dpMove);
printf("删除完成!\n");
return;
}
pMove = pMove->next;
dpMove = pMove->next;
}
printf("未找到匹配结点");
}
void printlist(L* head)
{
L* pMove = head->next;
if(pMove==NULL)
{
printf("链表无数据\n");
return;
}
printf("头");
while(pMove)
{
printf("->%d",pMove->data);
pMove = pMove->next;
}
printf("->尾\n");
}
void detelelist(L* head)
{
L* pMove = head->next;
while(pMove)
{
head->next = pMove->next;
free(pMove);
pMove = head->next;
printlist(head);
}
head = NULL;
}
void main()
{
L* list = creatorList();
L* newNode;
int data;
while(1)
{
printf("请输入结点数据(0为停止输入):");
scanf("%d",&data);
if(data==0)
break;
newNode = creatorNode(data);
insertNode(list,newNode);
printf("输出链表:\n");
printlist(list);
}
printf("请输入所要查找的数据:");
scanf("%d",&data);
queryNode(list,data);
printf("\n请输入所要修改的结点数据:");
scanf("%d",&data);
changeNode(list,data);
printlist(list);
printf("请输入所要删除的结点:");
scanf("%d",&data);
deteleNode(list,data);
printlist(list);
getchar();getchar();
printf("删除链表数据:\n");
detelelist(list);
}
代码里插入结点函数我用了排序插入法,销毁链表函数我用了头删法,大家可以使用上面的其他方法,希望此篇文章能对正在学习单链表的码农们能有所帮助,欢迎在评论区里讨论,谢谢大家!!!