循环链表
在单链表中,存在这样一个问题,如果不从头结点出发,就无法访问到全部结点。
而为了解决这个问题,只需要将单链表终端结点的指针域由空指针改为指向头结点。这种方法类似于静链表中,最后一个元素的游标存放第一个有数值的元素的下标,这两者有异曲同工之妙。
将单链表终端结点的指针域端由空指针改为指向头结点,就使单链表形成了一个环,这种头尾相接的链表叫做单循环链表,简称循环链表。
一、循环链表的创建(结合图片一起看)
此处及以下使用了知识点(指针的指针),不明白的朋友可以了解
指针作为函数参数传递以及指针的指针
#include <stdio.h>
#include <stdlib.h>
typedef struct List
{
int data;
struct List* next;
}list,*p_list;
//创建循环链表
void creat_list(list** p) //带**的为指向指针的指针(双重指针),因此**p为头指针(指向头结点的指针),*p为头结点
//如果链表为空,则创建一个链表,指针域指向自己,否则寻找尾结点
{ //将尾结点的指针指向这个新结点,新结点的指针域指向头结点
int item; //数据存储变量
list* temp; //作为新结点
list* target; //作为尾结点
printf("输入结点的值,输入0结束\n");
while (1)
{
scanf("%d", &item);
if (item == 0)return;
if (*p == NULL) //如果输入的链表为空,则创建一个新的结点,使其next指向自己 (*head)->next=head;
{
*p = (list*)malloc(sizeof(list));
if (!*p)exit(0);
(*p)->data = item;
(*p)->next = *p;
}
else
{//输入的链表不为空,寻找链表的尾结点,使尾结点的next=新节点,新节点的next指向头结点
for (target = *p; target->next != *p; target = target->next);//此时target为尾结点
temp = (list*)malloc(sizeof(list));//创建新结点
if (!item)exit(0);
temp->data = item; //数据存入新结点数据域
temp->next = *p; //新结点指向头结点
target->next = temp; //将尾结点与新结点链接
}
}
}
二、循环链表的遍历
//循环链表的遍历
void show(list* p) //*p为头结点,传入的是头结点
{
list* temp;
temp = p;
do
{
printf("%5d", temp->data);
temp = temp->next;
} while (temp != p); //当前结点不为头结点
printf("\n");
}
三、循环链表的插入
//循环链表的插入
void insert(list** pNode, int place, int num) //传入的是头指针
{
list* temp, * target;
int i;
if (place == 1)
{
temp = (list*)malloc(sizeof(list)); //创建新结点
if (!temp)exit(0);
temp->data = num;
for (target = *pNode; target->next != *pNode; target = target->next); //寻找尾结点
temp->next = *pNode; //新结点指向头结点
target->next = temp; //尾结点指向新结点
*pNode = temp; //注意:改变主函数中的头结点,新结点作为新的头结点
}
else
{
for (i = 1, target = *pNode; target->next != *pNode && i != place - 1; target = target->next); //寻找插入位置
temp = (list*)malloc(sizeof(list)); //创建新结点
temp->data = num;
temp->next = target->next; //插入结点指向插入位置后的结点
target->next = temp; //插入位置前的结点指向插入结点
}
}
四、循环链表的删除
//循环链表的删除
void delete(list**pNode,int place) //传入的是头指针
{
list* temp, * target;
int i;
temp = *pNode;
if(temp == NULL) //首先判断链表是否为空
{
printf("这是一个空指针,无法删除\n");
return;
}
if (place == 1) //如果删除的是头结点
{ //特殊处理,先找到尾结点,更新头结点为原头结点的下一结点,使尾结点的next指向新头结点,释放原头结点
for (target = *pNode; target->next != *pNode; target = target->next); //寻找尾结点
temp = *pNode;
*pNode = (*pNode)->next; //更新头结点为原头结点的下一结点
target->next = *pNode; //尾结点指向新头结点
free(temp); //释放原头结点
}
else//删除其他结点
{ //寻找删除结点的前一个结点
for (i = 1, target = *pNode; target->next != *pNode && i != place - 1; target = target->next, i++);
if (target->next == *pNode) //如果删除结点为尾结点
{
for (target = *pNode; target->next->next != *pNode; target = target->next);//寻找尾结点的前一个结点
temp = target->next; //temp为尾结点
target->next = *pNode; //删除结点的前一个结点指向头结点
free(temp); //释放尾结点
}
else//删除其他情况的结点时
{ //此时target为删除结点的前一个结点
temp = target->next; //temp为删除结点
target->next = temp->next; //删除结点的前一个结点与删除结点的后一个结点链接
free(temp); //释放删除结点
}
}
//总结:
//target为删除结点的前一个节点为
//temp始终为删除结点
//先将删除结点的前一个节点与删除结点的后一个结点链接,即target->next=temp->next;
//再释放删除结点 free(temp);
}
五、查找值
//查找值
int findval(list* pNode, int val) //传入的是头结点
//寻找值,返回位置
{
int i = 1; //从1开始,因为头结点也有值
list* node;
node = pNode;
while (node->data != val && node->next != pNode)
{
i++;
node = node->next;
}
if (node->next == pNode && node->data != val) //检索到尾结点时跳出,因此还要检测目标是否为尾结点的data
{
return -1;
}
return i;
}
完整代码
#include <stdio.h>
#include <stdlib.h>
typedef struct List
{
int data;
struct List* next;
}list,*p_list;
//创建循环链表
void creat_list(list** p) //带**的为指向指针的指针(双重指针),因此**p为头指针(指向头结点的指针),*p为头结点
//如果链表为空,则创建一个链表,指针域指向自己,否则寻找尾结点
{ //将尾结点的指针指向这个新结点,新结点的指针域指向头结点
int item; //数据存储变量
list* temp; //作为新结点
list* target; //作为尾结点
printf("输入结点的值,输入0结束\n");
while (1)
{
scanf("%d", &item);
if (item == 0)return;
if (*p == NULL) //如果输入的链表为空,则创建一个新的结点,使其next指向自己 (*head)->next=head;
{
*p = (list*)malloc(sizeof(list));
if (!*p)exit(0);
(*p)->data = item;
(*p)->next = *p;
}
else
{//输入的链表不为空,寻找链表的尾结点,使尾结点的next=新节点,新节点的next指向头结点
for (target = *p; target->next != *p; target = target->next);//此时target为尾结点
temp = (list*)malloc(sizeof(list));//创建新结点
if (!item)exit(0);
temp->data = item; //数据存入新结点数据域
temp->next = *p; //新结点指向头结点
target->next = temp; //将尾结点与新结点链接
}
}
}
//循环链表的遍历
void show(list* p) //*p为头结点,传入的是头结点
{
list* temp;
temp = p;
do
{
printf("%5d", temp->data);
temp = temp->next;
} while (temp != p); //当前结点不为头结点
printf("\n");
}
//循环链表的插入
void insert(list** pNode, int place, int num) //传入的是头指针
{
list* temp, * target;
int i;
if (place == 1)
{
temp = (list*)malloc(sizeof(list)); //创建新结点
if (!temp)exit(0);
temp->data = num;
for (target = *pNode; target->next != *pNode; target = target->next); //寻找尾结点
temp->next = *pNode; //新结点指向头结点
target->next = temp; //尾结点指向新结点
*pNode = temp; //注意:改变主函数中的头结点,新结点作为新的头结点
}
else
{
for (i = 1, target = *pNode; target->next != *pNode && i != place - 1; target = target->next); //寻找插入位置
temp = (list*)malloc(sizeof(list)); //创建新结点
temp->data = num;
temp->next = target->next; //插入结点指向插入位置后的结点
target->next = temp; //插入位置前的结点指向插入结点
}
}
//循环链表的删除
void delete(list**pNode,int place) //传入的是头指针
{
list* temp, * target;
int i;
temp = *pNode;
if(temp == NULL) //首先判断链表是否为空
{
printf("这是一个空指针,无法删除\n");
return;
}
if (place == 1) //如果删除的是头结点
{ //特殊处理,先找到尾结点,更新头结点为原头结点的下一结点,使尾结点的next指向新头结点,释放原头结点
for (target = *pNode; target->next != *pNode; target = target->next); //寻找尾结点
temp = *pNode;
*pNode = (*pNode)->next; //更新头结点为原头结点的下一结点
target->next = *pNode; //尾结点指向新头结点
free(temp); //释放原头结点
}
else//删除其他结点
{ //寻找删除结点的前一个结点
for (i = 1, target = *pNode; target->next != *pNode && i != place - 1; target = target->next, i++);
if (target->next == *pNode) //如果删除结点为尾结点
{
for (target = *pNode; target->next->next != *pNode; target = target->next);//寻找尾结点的前一个结点
temp = target->next; //temp为尾结点
target->next = *pNode; //删除结点的前一个结点指向头结点
free(temp); //释放尾结点
}
else//删除其他情况的结点时
{ //此时target为删除结点的前一个结点
temp = target->next; //temp为删除结点
target->next = temp->next; //删除结点的前一个结点与删除结点的后一个结点链接
free(temp); //释放删除结点
}
}
//总结:
//target为删除结点的前一个节点为
//temp始终为删除结点
//先将删除结点的前一个节点与删除结点的后一个结点链接,即target->next=temp->next;
//再释放删除结点 free(temp);
}
//查找值
int findval(list* pNode, int val) //传入的是头结点
//寻找值,返回位置
{
int i = 1; //从1开始,因为头结点也有值
list* node;
node = pNode;
while (node->data != val && node->next != pNode)
{
i++;
node = node->next;
}
if (node->next == pNode && node->data != val) //检索到尾结点时跳出,因此还要检测目标是否为尾结点的data
{
return -1;
}
return i;
}
int main()
{
list* head = NULL;
list* val = NULL;
int place, num;
creat_list(&head);
printf("原始的链表:");
show(head);
printf("请输入要删除的位置:");
scanf("%d", &place);
delete(&head, place);
show(head);
printf("请输入插入的位置和数据,用空格隔开:");
scanf("%d%d", &place, &num);
insert(&head, place, num);
show(head);
printf("请输入你想要查找的值:");
scanf("%d", &num);
place = findval(head, num);
if (place != -1)printf("找到的值的位置是place=%d\n", place);
else
printf("没有找到该值\n");
return 0;
}
转载于:https://www.cnblogs.com/dakewei/p/11378713.html