单链表的实现–C 语言版,详细讲解+代码实现
文章目录
前言
`
继上一篇单链表的讲解和实现,现在进行循环单链表的实现。
一、循环单链表是什么?
所谓循环单链表,就是在单链表的基础上,将序列进行头尾相连,使链表变为逻辑上的环形。
简单来说,循环链表,就是在单链表的基础上,将单链表的最后一个元素的指针,由空,变为了指向头结点。
二、代码实现
1.设计数据结构
为方便讲解和理解,我们还是选择将链表中存储的数据设计为整型,同时头节点的data中存储的是整个循环单链表的长度。
typedef struct Node
{
int data;
struct Node* next;
}Node;```
2.循环单链表的初始化
由于循环单链表是逻辑上的环形结构,首位相连,所以当我们初始化的时候,链表中实际上只有一个头节点,这时,头节点的指针指向自己。
同时,由于我们设计的单链表的头指针存储的数据是链表的长度,所以,我们初始化的时候也将头节点的data初始化为0.
Node* init(){
Node* node=(Node*)malloc(sizeof(Node));
node->data=0;
node->next=node;
return node;
}
3.头插法的实现
个人认为,单循环链表的头插法和单链表的头插法几乎是一样的
思路和单链表的头插法一样
- 首先定义一个结点用来容纳数据
- 将这个结点的next指针指向头节点的next
- 将头指针的next指向新定义的结点
- 将头指针的data+1
//头插法
void head_insert(Node* node , int data){
Node* curnode=(Node*)malloc(sizeof(Node));
curnode->data=data;
curnode->next=node->next;
node->next=curnode;
node->data++;
}
4.尾插法的实现
尾插法好像也单链表基本一样(手动捂脸)。
思路步骤如下:
- 定义一个结点来容纳新的数据
- 定义一个辅助结点用来辅助操作,首先将辅助结点赋值为首元结点(头节点后的第一个结点)用来循环寻找最后一个节点
- 通过辅助结点来循环,直到辅助结点的next的next为头节点的next,这就说明当前辅助结点的位置为头节点的前一个,辅助结点的next就是头节点,也就是说他就是理论上链表的最后一个。
- 此时将新的结点的指针指向头节点,同时将辅助结点的指针指向新结点实现拼接。
- 将头指针的data+1
//尾插法
void tail_insert(Node* node,int data){
Node* curnode=(Node*)malloc(sizeof(Node));
Node* helpnode=(Node*)malloc(sizeof(Node));
curnode->data=data;
helpnode = node->next;
while(helpnode){
if(helpnode->next->next==node->next){
curnode->next = helpnode->next;
helpnode->next = curnode;
node->data++;
break;
}
helpnode = helpnode->next;
}
}
5. 结点的删除
删除好像也和单链表一样?(手动思考)
思路步骤如下
- 初始化一个当前节点curnode和一个当前结点的前一个结点prenode,
- 用当前节点curnode来进行循环,当curnode的next和头节点的next地址一样时,说明循环经过一周,停止循环。
- 在每一次循环时,判断当前结点的data和要删除的data是否一样,当一样的时候,将prenode的next指向curnode的next,并释放curnode
- 将头节点的data值+1
//删除
void delete(Node* node,int data){
Node* curnode=(Node*)malloc(sizeof(Node));
Node* prenode=(Node*)malloc(sizeof(Node));
prenode = node;
curnode= node->next;
while(curnode){
if(curnode->next==node->next){
break;
}
if(curnode->data == data){
prenode->next = curnode->next;
free(curnode);
node->data--;
break;
}
}
}
6. 结点的遍历
感觉…单链表和循环链表,好像,都一样啊,是我的错觉吗?
遍历的步骤:
- 初始化一个结点用来存储当前结点的地址
- 用该节点进行循环,并输出当前结点的data。
//遍历
void show(Node* node){
Node* curnode=(Node*)malloc(sizeof(Node));
curnode=node->next;
while (curnode)
{
if(curnode->next==node->next){
break;
}else{
printf("%d\n",curnode->data);
curnode=curnode->next;
}
}
}
总结
这单链表和循环单链表,实际上就是多了一个最后一个结点地址指向头节点,没了。
(doge)(doge)(doge)(doge)(doge)(doge)