目录
循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。
一、循序链表简介
根据前面的线性表,来完成循环链表,预知了解线性表知识,请前往CSDN此处;
1、循环链表的定义
循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。
循环链表的逻辑关系图如下:
2、循环链表特点
- 无须增加存储量,仅对表的链接方式稍作改变,即可使得表处理更加方便灵活。
二、循环链表的运算
- 插入节点:在循环链表中插入一个新的节点需要找到插入位置,修改相关节点的指针使其形成环。插入位置可以通过遍历找到,也可以通过一些技巧(如双指针法)快速找到。
- 删除节点:要删除一个节点,需要找到该节点并修改相关节点的指针使其形成环。要删除的节点可能是头节点或尾节点,也可能是链表中的任意节点。删除节点时需要处理多种情况。
- 遍历链表:由于循环链表的最后一个节点的指针指向第一个节点,因此可以从任意节点开始遍历整个链表。遍历时需要注意不要形成死循环。
- 查找元素:可以通过遍历循环链表来查找指定元素,也可以使用哈希表等数据结构来加速查找。
三、循环链表的实现
1.简单链表的定义
/*简单链表的定义*/
typedef struct node
{
DataType data; /*数据域*/
struct node *next; /*指针域*/
}SingleLinkList, SingleLinkNode;
2、初始化
/*1. 初始化*/
int init(SingleLinkList **Head)
{
if(1)
{
/*申请内存*/
(*Head) = (SingleLinkList*)malloc(sizeof(SingleLinkList));
/*判断内存申请是否成功*/
if(*Head == NULL)
{
printf("申请内存错误, 初始化失败![100001]\n");
return 100001;
}
(*Head)->next = *Head;
/*循环链表*/
/*
(*Head)->next = *Head;
*/
return 0;
}
else
{
printf("该链表已经初始化!请删除后再执行此操作![100002]\n");
return 100002;
}
}
3、插入元素
/*3. 插入元素,头插法*/
int insert_head(SingleLinkList **Head, DataType x)
{
SingleLinkNode *newNode;if(0)
{
printf("链表未初始化![100003]\n");
return 100003;
}
newNode = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
if(!newNode)
{
printf("申请节点内存空间失败![100004]\n");
return 100004;
}
newNode->data = x;
newNode->next = *Head;(*Head)->next = newNode;
return 0;
}
/*3. 插入元素, 尾插法*/
int insert_tail(SingleLinkList **Head, DataType x)
{
SingleLinkNode *newNode;
SingleLinkNode *p;if(0)
{
printf("链表未初始化![100003]\n");
return 100003;
}
newNode = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
if(!newNode)
{
printf("申请节点内存空间失败![100004]\n");
return 100004;
}newNode->data = x;
newNode->next = *Head;
/*
循环链表
newNode->next = *Head;
*/p = (*Head);/**/
while(p->next!=*Head)
{
p = p->next;/*p指向原来的下一个节点*/
}p->next = newNode;/*p指向头节点*/
return 0;
}/*3. 插入元素,在位置i处插入元素x */
int insert(SingleLinkList **Head, int i, DataType x)
{
int j;
SingleLinkNode *p;
SingleLinkNode *newNode;
/*对i进行判断,0<i<=length+1*/
if(i<1 || i>length(*Head)+1)
{
printf("位置i不是链表有效位置![100005]\n");
return 100005;
}
p = (*Head);
j = 1;while(j<i)
{
j++;
p = p->next;
}newNode = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
/*此处省略检测newNode是否申请成功*/newNode->data = x;
newNode->next = p->next;
p->next = newNode;
return 0;
}
4、删除元素
/*3. 删除元素, 删除值为x的元素*/
int delete(SingleLinkList **Head, DataType x)
{
int i;
int j;SingleLinkNode *p;
SingleLinkNode *q; /*要删除的元素x*/i = find(*Head,x);
if(!i)
{
printf("元素x【%d】不存在!100006\n", x);
return 100006;
}
p = (*Head);
j=1;while(j<i)
{
j++;
p = p->next;
}
q = p->next;
p->next = q->next;free(q); /*释放内存*/
return 0;
}
5、查找元素x,并指定位置
/*5. 查找值为x的元素,返回位置i */
int find(SingleLinkList *Head, DataType x)
{
int i;
SingleLinkNode *p;i = 1;
p = Head->next;while( p!= Head && p->data != x) /*while( p!= Head && p->data != x) */
{
i++;
p = p->next;
}if(p==Head) /* if(p->next == Head) */
{
return 0;
}
else
{
return i;
}}
6、求链表长度
/*6. 求链表的长度 */
int length(SingleLinkList *Head)
{
int len=0;
SingleLinkNode *p;p = Head->next;
while(p!=Head) /* while(p!=Head) */
{
len++;
p = p->next;
}
return len;
}
7、输出链表
void print(SingleLinkList *Head)
{
SingleLinkNode *p;
int i=0;p = Head->next;
if(p==Head) /* if(p!=Head) */
{
printf("链表为空!\n");
return;
}
while(p!=Head) /* while(p!=Head) */
{
printf("Node[%d]. = %d\n", ++i, p->data);
p = p->next;
}
}
四、完整代码
1、main.c
#include <stdio.h>
#include <string.h>
#include "SingleLinkList.h"
#include "welcome.h"
int main(int argc, char* argv[])
{
SingleLinkList *Head;
DataType x;
int i,m,n,cmd;for(i=0;i<strlen(welcome);i++)
{
printf("%c",welcome[i]);
for(m=0;m<1000;m++)
for(n=0;n<1000;n++)
{
;
}
}printf("-----------简单链表演示程序----------\n");
do
{
printf("1. 初始化链表表\n");
printf("2. 插入元素(头插法)\n");
printf("3. 插入元素(尾插法)\n");
printf("4. 插入元素(在位置i插入)\n");
printf("5. 查找元素x\n");
printf("6. 求链表长度\n");
printf("7. 输出链表\n");
printf("8. 删除元素\n");
printf("9. 帮助\n");
printf("0. 退出\n");
printf("请输入您要进行的操作(1~9,0退出):");
scanf("%d", &cmd);
switch(cmd)
{
case 1:
if(!init(&Head))
{
printf("链表已初始化!\n");
}
break;
case 2:
printf("请输入插入元素x:x=");
scanf("%d",&x);
if(!insert_head(&Head,x))
{
printf("元素(%d)已插入\n", x);
}
break;
case 3:
printf("请输入插入元素x:x=");
scanf("%d",&x);
if(!insert_tail(&Head,x))
{
printf("元素(%d)已插入\n", x);
}
break;
case 4:
printf("请输入插入元素位置i和元素x(i,x):");
scanf("%d,%d", &i, &x);
if(!insert(&Head, i, x))
{
printf("已在位置(%d)插入元素(%d)!\n",i, x);
}
break;
case 5:
printf("请输入要查找的元素x:");
scanf("%d", &x);
if(i = find(Head,x))
{
printf("元素%d存在,在链表位置%d.\n", x, i);
}
else
{
printf("在链表中未找到元素x。\n");
}
break;
case 6:
printf("链表的长度为:%d\n", length(Head));
break;
case 7:
print(Head);
break;
case 8:
printf("请输入要删除的元素x:");
scanf("%d", &x);
if(!delete(&Head, x))
{
printf("元素x【%d】已删除!\n", x);
}
break;
case 10:
printf(" 本程序为链表的演示程序,由林振发设计开发,程序完成了链表的删除,添加,查询等功能!!!!!\n");
break;
}
}while(cmd != 0);return 0;
}
2.SingleLinkList.c
/*
SingleLinkList.c
*/
#include "SingleLinkList.h"
#include <stdlib.h>
#include <stdio.h>/*1. 初始化*/
int init(SingleLinkList **Head)
{
if(1)
{
/*申请内存*/
(*Head) = (SingleLinkList*)malloc(sizeof(SingleLinkList));
/*判断内存申请是否成功*/
if(*Head == NULL)
{
printf("申请内存错误, 初始化失败![100001]\n");
return 100001;
}
(*Head)->next = *Head;
/*循环链表*/
/*
(*Head)->next = *Head;
*/
return 0;
}
else
{
printf("该链表已经初始化!请删除后再执行此操作![100002]\n");
return 100002;
}
}
/*2. 插入元素,头插法*/
int insert_head(SingleLinkList **Head, DataType x)
{
SingleLinkNode *newNode;if(0)
{
printf("链表未初始化![100003]\n");
return 100003;
}
newNode = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
if(!newNode)
{
printf("申请节点内存空间失败![100004]\n");
return 100004;
}
newNode->data = x;
newNode->next = *Head;(*Head)->next = newNode;
return 0;
}
/*2. 插入元素, 尾插法*/
int insert_tail(SingleLinkList **Head, DataType x)
{
SingleLinkNode *newNode;
SingleLinkNode *p;if(0)
{
printf("链表未初始化![100003]\n");
return 100003;
}
newNode = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
if(!newNode)
{
printf("申请节点内存空间失败![100004]\n");
return 100004;
}newNode->data = x;
newNode->next = *Head;
/*
循环链表
newNode->next = *Head;
*/p = (*Head);/**/
while(p->next!=*Head)
{
p = p->next;/*p指向原来的下一个节点*/
}p->next = newNode;/*p指向头节点*/
return 0;
}
/*2. 插入元素,在位置i处插入元素x */
int insert(SingleLinkList **Head, int i, DataType x)
{
int j;
SingleLinkNode *p;
SingleLinkNode *newNode;
/*对i进行判断,0<i<=length+1*/
if(i<1 || i>length(*Head)+1)
{
printf("位置i不是链表有效位置![100005]\n");
return 100005;
}
p = (*Head);
j = 1;while(j<i)
{
j++;
p = p->next;
}newNode = (SingleLinkNode*)malloc(sizeof(SingleLinkNode));
/*此处省略检测newNode是否申请成功*/newNode->data = x;
newNode->next = p->next;
p->next = newNode;
return 0;
}
/*3. 删除元素, 删除值为x的元素*/
int delete(SingleLinkList **Head, DataType x)
{
int i;
int j;SingleLinkNode *p;
SingleLinkNode *q; /*要删除的元素x*/i = find(*Head,x);
if(!i)
{
printf("元素x【%d】不存在!100006\n", x);
return 100006;
}
p = (*Head);
j=1;while(j<i)
{
j++;
p = p->next;
}
q = p->next;
p->next = q->next;free(q); /*释放内存*/
return 0;
}
/*5. 查找值为x的元素,返回位置i */
int find(SingleLinkList *Head, DataType x)
{
int i;
SingleLinkNode *p;i = 1;
p = Head->next;while( p!= Head && p->data != x) /*while( p!= Head && p->data != x) */
{
i++;
p = p->next;
}if(p==Head) /* if(p->next == Head) */
{
return 0;
}
else
{
return i;
}}
/*4. 链表长度*/
int length(SingleLinkList *Head)
{
int len=0;
SingleLinkNode *p;p = Head->next;
while(p!=Head) /* while(p!=Head) */
{
len++;
p = p->next;
}
return len;
}/*6.输出链表*/
void print(SingleLinkList *Head)
{
SingleLinkNode *p;
int i=0;p = Head->next;
if(p==Head) /* if(p!=Head) */
{
printf("链表为空!\n");
return;
}
while(p!=Head) /* while(p!=Head) */
{
printf("Node[%d]. = %d\n", ++i, p->data);
p = p->next;
}
}
3.SingleLinKList.h
/*
SingleLinkList.h
*/typedef int DataType;
/*简单链表的定义*/
typedef struct node
{
DataType data; /*数据域*/
struct node *next; /*指针域*/
}SingleLinkList, SingleLinkNode;
/*1. 初始化*/
int init(SingleLinkList **Head);/*2. 插入元素,头插法*/
int insert_head(SingleLinkList **Head, DataType x);/*2. 插入元素, 尾插法*/
int insert_tail(SingleLinkList **Head, DataType x);/*2. 插入元素,在位置i处插入元素x */
int insert(SingleLinkList **Head, int i, DataType x);/*3. 删除元素, 删除值为x的元素*/
int delete(SingleLinkList **Head, DataType x);/*5. 查找值为x的元素,返回位置i */
int find(SingleLinkList *Head, DataType x);/*6. 求链表的长度 */
int length(SingleLinkList *Head);/*7.输出链表*/
void print(SingleLinkList *Head);
4.welcome.h
char welcome[]=(
" lovelove lovelove\n"
" lovelovelove lovelovelove\n"
" lovelovelovelove lovelovelovelove\n"
" lovelovelovelovelove lovelovelovelovelove\n"
" lovelovelovelovelovelo lovelovelovelovelovele\n"
" lovelovelovelovelovelovelolovelovelovelovelovelovee\n"
" lovelovelovelovelovelolovellovelovelovelovelovele\n"
" lovelovelovelovelovelovelolovelovelovelovelove\n"
" lovelovelovelovelovelovelovloveloveloveloe\n"
" lovelovelovelovelovelovelovloveloveloe\n"
" lovelovelovelovelolovelovelloveloe\n"
" lovelovelovelovelovelovelovele\n"
" lovelovelovelovelovelocele\n"
" lovelovelovelovelovele\n"
" lovelovelovelovele\n"
" loveloveloveve\n"
" lovelovelo\n"
" lovelov\n"
" love\n"
" 爱\n");
五、运行结果截图
六、总结
循环链表是一种特殊的数据结构,它由一组节点组成,每个节点包含一个指向下一个节点的指针,最后一个节点的指针指向第一个节点,形成一个环。循环链表可以用来解决一些需要从链表任意节点开始遍历整个链表的问题。
- 循环链表的特点是最后一个节点的指针不是空(NULL),而是指向第一个节点,从而形成了一个环。
- 循环链表的运算主要包括插入节点、删除节点、遍历链表、查找元素和修改节点值等操作。
- 插入节点和删除节点需要修改相关节点的指针,使其形成环;遍历链表可以从任意节点开始,但要注意避免形成死循环;查找元素可以通过遍历循环链表来实现,也可以使用其他数据结构来加速查找。
- 在实际应用中,可以根据具体需求选择是否使用循环链表。如果需要从链表任意节点开始遍历整个链表,则可以考虑使用循环链表。
- 循环链表相对于普通链表来说比较复杂,需要注意各种情况的处理。
七、参考文献
- 数据结构c语言版本(李刚)
- 百度查询
- csdn博客