之前在复习的时候,复习到链表。就总结了这篇,如果你看到这篇博客,希望可以帮到你!
大家在学习C语言的时候最常用的就是数组了,但是其实链表的作用也是非常大的。首先来给大家share一下数组和链表的结构有哪些不同!
一:结构上的不同
首先链表是链式的存储结构,而数组则是顺序的存储结构。数组是把所有的元素依次的存储,而链表则是通过结构体指针来链接元素与元素。对于基本操作来说,链表的插入与删除就较为简单,不用移动每一个元素,但是寻找起来就很费劲,寻找一个元素,需要访问其前边所有的元素。而数组的话,是支持随机访问的,寻找起来也是很方便的,但是插入和删除就比较麻烦,首先数组是设定固定长度的,当达到最大长度时候,扩充数组的长度就没有链表方便。
二:相同点
两种结构均可实现顺序存储。
三:什么时候用数组?什么时候用链表?
如果你需要的一块动态的存储空间,且数据的多少不确定,变化比较大就可以使用链表。但是如果你不需要频繁插入删除操作,切对空间长度没有要求的时候就推荐是用数组。
四:链表的组成
链表是由一系列的节点组成。每个节点包含两个部分:数据域和指针域。数据域是用来存储数据元素的,指针域则是存储下一个节点地址的。且在物理的存储结构上是非连续、非顺序的存储结构,每个元素的逻辑顺序也是通过结构体中的指针链接次序实现的。
五:关于链表的基本操作
-
链表数据结构的定义
-
此结构体中定义了一个integer型的数据,即为每个节点数据域存放的数据类型。定义了一个结构体类型的指针,通过此指针来链接各节点。
-
typedef struct LinkList{
int date;
struct LinkList *next;
}Node,linkList;
- 链表的创建:
- 初始化含有n个的节点的链表,思想:通过循环先将当前节点初始化,之后不断用当前节点指向末尾节点,并将末尾节点的指针域设为空。
linkList * creat_LinkList(int n){
linkList *PHead ,*PCurrent, *PEnd; //创立头节点PHead、当前节点PCurrent、末尾节点PEnd
PHead = (linkList *)malloc( sizeof(linkList));
if( PHead == NULL){
return NULL;
}
PEnd = PHead; //开始阶段,未插入节点前只有头节点,所以末尾节点和头节点是一个。
//此时开始创建节点,
for (int i = 1; i <= n; i++)
{
//初始化当前节点
PCurrent = (linkList *)malloc( sizeof(linkList));
printf("please input value of the NO%d date !",i);
scanf("%d",PCurrent->date);
PCurrent -> next = NULL;
//当前节点指向末尾节点。
PEnd -> next = PCurrent;
PEnd = PCurrent;
}
//将末尾节点的指针域设为空。
PEnd->next = NULL;
return PHead;
}
- 修改链表节点的值
- 思想:传入链表和要修改的链表节点,用变量flag来标记节点,用暂时替代链表replace取代传入链表,与flag同事进行遍历,如果当flag和传入链表节点相同则找到要修改的节点,进行修改。
void alter_LinkListNode(linkList *List ,int alter_position){
int flag = 0;
linkList * replace = List;
//运用while循环来判定是否找到要修改节点的位置,找到则跳出循环。replace则是要修改的节点。
while (flag < alter_position && replace != NULL )
{
replace = replace ->next ;
flag++;
}
if( replace != NULL){
printf("please input date of you want !");
scanf("%d",&replace -> date);
}else
{
printf("you want alter the date doesn't exist!");
}
}
- 删除链表节点:
- 此时跟大家说一下,删除的操作如图所示:
如图所示: 删除链表节点其实就是将要【 删除节点的上一个节点 】的指针域所指向的下一节点的地址改成 【 删除节点的下一个节点 】的地址,此操作之后,将要删除的节点的内存空间释放掉。
思想:首先要了解free的概念。C语言中并没有像JAVA一样的废弃内存空间回收机制,所以对于不用的内存空间需要手动释放,这时便用到了free。在删除链表节点的时候,很多人都会直接写成pre_Node -> next = pre_Node -> next -> next,然后free(pre_Node -> next)。然而此时你释放掉pre_Node ->next之后,后面的链表节点就找不到了,因为上一步你是直接把pre_Node -> next直接释放掉了,这样整个链表就断掉,后面当然就找不到了。free(pre_Node) 是指删除pre_Node指向节点所占的内存,不是删除pre_Node本身所占内存。所以我们要定义一个临时的节点pre_Node,来代替要删除节点的上一节点。
void delete_LinkListNode( linkList *List , int deleteNode_date){
linkList * delete_Node ,* pre_Node = List;
while ( pre_Node != NULL )
{
if( pre_Node -> next -> date == deleteNode_date && pre_Node != NULL ){
delete_Node = pre_Node ->next; //此时delete_Node和pre_Node -> next指向的都是pre_Node->next存储空间的地址。
//这时free(delete_Node)之后,还有pre_Node -> next保留以保证链表不会断掉。
pre_Node ->next = delete_Node ->next;
free(delete_Node);
printf("删除成功!");
}else
{
pre_Node = pre_Node -> next;
}
}
}
- 插入链表节点
- 如图所示:和删除的操作基本相同,在插入之前节点p的指针域p->next指向的是节点H,在插入节点之后,插入的节点就相当于H的位置,所以此时只需要把H节点与插入的节点连接起来,同时将插入的节点与P链接起来就可以了。即为:q -> next = p -> next ; p -> next = q ; 此时两个步骤顺序是不可以更改的,如果你先将p -> next = q ; 然后将q -> next = p ->next ; 此时是把插入节点和插入节点的下一节点连接了起来,而上一节点和插入节点就断掉了,切记!!!!!
通过形参传入链表以及要插入链表节点的位置,以及插入节点数据域的数据。如果遍历链表找到标记与节点相同,则证明找到,否则继续遍历。
void insert_LinkLstNode(linkList *List , int insert_position ,int insert_date){
int flag = 0; //flag用于标记节点,判断时候找到插入位置
linkList * q ,* p = List;
if ( insert_position < 0 || p == NULL)
{
printf("插入失败");
}
else
{
while (p != NULL)
{
if (insert_position == flag )
{
q = (linkList *)malloc(sizeof(linkList));
q -> date = insert_date;
q -> next = p -> next;
p -> next = q;
break;
}
else
{
flag++;
p = p -> next;
}
}
}
}
- 打印列表
-
打印链表就比较简单了,只需要遍历即可。
-
//打印链表。思想:打印列表便比较简单,直接传入一个头指针,之后遍历整个链表进行输入。
void print_LinkList(linkList * H){
linkList * P = H ->next;
printf("the value of date is : %5d\n",P->date);
while (P != NULL)
{
P = P->next;
}
}
如果您看完有任何不理解的地方,或者有任何补充,欢迎在下方留言!