循环链表的定义和特点
定义
链表是一种常见的数据结构,用于存储一系列的元素。链表由多个节点组成,每个节点包含两部分:数据域和指针域。数据域用于存储具体的数据,而指针域用于指向下一个节点。
循环链表是一种特殊类型的链表,最后一个节点的指针域不是指向空(NULL),而是指向链表的第一个节点,形成一个循环。循环链表可以通过任意一个节点开始遍历,直到回到起始节点。循环链表的定义和单链表类似,每个节点包含数据域和指针域。不同之处在于,循环链表的最后一个节点的指针域指向第一个节点。
特点
-
循环性:循环链表的最后一个节点的指针域指向第一个节点,形成一个循环。这意味着可以通过任意一个节点开始遍历,直到回到起始节点。
-
灵活性:循环链表可以在任意位置插入或删除节点,不需要移动其他节点。
-
内存效率:循环链表只需要为每个节点分配内存空间,不会浪费额外的内存空间。
-
随机访问性能较差:循环链表的节点不是连续存储的,因此无法通过索引直接访问节点,需要从任意一个节点开始遍历。
总之,循环链表是一种特殊类型的链表,具有循环性质。它在某些场景下可以更方便地处理循环相关的问题,例如循环队列的实现。
基本运算
-
创建循环链表:创建一个空的循环链表,可以通过将最后一个节点的指针域指向第一个节点来形成循环。
-
插入节点:在循环链表的任意位置插入一个新节点。插入节点时,需要将新节点的指针域指向下一个节点,并将前一个节点的指针域指向新节点。
-
删除节点:从循环链表中删除一个节点。删除节点时,需要将前一个节点的指针域指向下一个节点,并释放被删除节点的内存空间。
-
遍历循环链表:从任意一个节点开始,按照指针域的指向依次访问每个节点,直到回到起始节点。遍历过程中可以对每个节点进行操作或打印节点的值。
-
查找节点:根据给定的值或条件,在循环链表中查找指定的节点。可以从任意一个节点开始遍历,逐个比较节点的值或条件,直到找到目标节点或遍历完整个循环链表。
-
修改节点值:根据给定的节点位置或条件,修改循环链表中指定节点的值。
这些基本运算可以通过遍历和操作循环链表的节点来实现。需要注意的是,在处理循环链表时,需要特别注意循环的终止条件,以避免陷入无限循环。
循环链表的实现
初始化
/*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)->next;
(*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->next = newNode;
return 0;
}
在位置i处插入元素x
/*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;
}
}
运行截图
以上为所有的运行截图
完整Demo
main.c
#include <stdio.h>
#include <string.h>
#include "SingleLinkList.c"
#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("10. 帮助\n");
printf("0. 退出\n");
printf("请输入您要进行的操作(1~6,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;
}
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)->next;
(*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->next = newNode;
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;
}
}
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);
welcome.h
char welcome[] = "\n\
[{+?]\n\
~++++{.\n\
!{{{{[}}{{{{{_. .{++++{ {{}{\n\
{++++++{++++++?}]++?{{_++{ -{++++}\n\
{+rr+r\+{+++++{$$ +++++++[{<<+++++{\n\
}++++++{+++++++{<{}+{$k {+++++}}{^\n\
}{++[{++++++++++++++{ _++++++++{,\n\
{++++++++++++++++++]}?+++++++++++{ \n\
{{++++++++++++++++++++++++++++++}\n\
{{+++++++++++++++++++++++_++++{\n\
{+++++++++++++++++++}}}}}}}++I\n\
{+++++++++++++++++++[}}}}}}}_+{\n\
[]++vY+++++++++++++++}}}}}}}}++{\n\
{++++X$X|+++++++++++++}}}}}[+++{\n\
{_++++X%$$qXXv\|XXX)++++++++++-^\n\
. :{++++++XX$$$$$qXv++++++++++++{\n\
l-++++++++++++++++++++++++++{\n\
I{++++++++++++++++++++++++{\n\
C0{}++++++++++++++++++-{0C\n\
COOOOO0{{[+++++++++_{{0OOO0C\n\
COOOOOOOOOOOOOOUCOOOOOOOOOOOOn<<<\n\
<<CLOOOOOOOOOOOOOOOOOOOOOOOOOOOOC ;<<<<<<\n\
<<<. COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC <<<<\n\
!<<. COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOCz\n\
<;!> COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC\n\
{QOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOL\n\
COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOY< <\n\
COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC<<<<<<`\n\
COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC\n\
[COOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOC\n\
]CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\n\
<< ^<^\n\
<< ^<^\n\
<< ^<^\n\
$$$$$$$$> O$$$$$$$z\n\n";
拓展题目
一元多项式的实现
一元多项式的定义
typedef struct node{
float coef; //系数
int expn; //指数
struct node *next; //后继
}pnode,*polynomial;
一元多项式的创建
//一元多项式创建
polynomial createpolyn(polynomial p,int m){
int i;
polynomial q,pre,s;
p = (polynomial)malloc(sizeof(pnode));
p->next = 0;
p->expn = -1;
for ( i = 0; i < m; i++)
{
s = (polynomial)malloc(sizeof(pnode));
printf("输入系数和指数");
scanf("%f%d",&s->coef,&s->expn);
pre = p;
q = p->next;
while (q&&q->expn<=s->expn)
{
pre = q;
q = q->next;
}
s->next = q;
pre->next = s;
}
printf("--创建成功--\n");
return p;
}
一元多项式的打印
//一元多项式打印
void pri (polynomial p){
polynomial q;
int id = 1;
q = p->next;
printf("加法运算后结果为:\n");
while (q)
{
printf("第%d个结点:系数%f,指数%d\n",id,q->coef,q->expn);
q = q->next;
id++;
}
}
一元多项式的相加
//一元多项式相加
polynomial addpolyn(polynomial pa,polynomial pb){
polynomial p1,p2,p3,q;
int sum;
p1 = pa->next;
p2 = pb->next;
p3 = pa;
while (p1&&p2)
{
if (p1->expn==p2->expn)
{
sum = p1->coef+p2->coef;
if (sum)
{
p1->coef = sum;
p3->next = p1;
p3 = p1;
p1 = p1->next;
q = p2;
p2 = p2->next;
free(q);
}else{
q = p1;
p1 = p1->next;
free(q);
q = p2;
p2 = p2->next;
free(q);
}
}else{
if (p1->expn<=p2->expn)
{
p3->next = p1;
p3 = p1;
p1 = p1->next;
}else{
p3->next = p2;
p3 = p2;
p2 = p2->next;
}
}
}
p3->next = p1?p1:p2;
free(pb);
return pa;
}
main方法
main(){
int m;
polynomial pa,pb,pc;
printf("==========创建一元多项式==========\n");
printf("创建A项数");scanf("%d",&m);
pa = createpolyn(pa,m);
printf("创建B项数");scanf("%d",&m);
pb = createpolyn(pb,m);
printf("==========一元多项式相加==========\n");
pc = addpolyn(pa,pb);
pri(pc);
printf("==========END==========");
}
运行截图
完整Demo
#include<stdio.h>
//一元多项式定义
typedef struct node{
float coef; //系数
int expn; //指数
struct node *next; //后继
}pnode,*polynomial;
//一元多项式创建
polynomial createpolyn(polynomial p,int m){
int i;
polynomial q,pre,s;
p = (polynomial)malloc(sizeof(pnode));
p->next = 0;
p->expn = -1;
for ( i = 0; i < m; i++)
{
s = (polynomial)malloc(sizeof(pnode));
printf("输入系数和指数");
scanf("%f%d",&s->coef,&s->expn);
pre = p;
q = p->next;
while (q&&q->expn<=s->expn)
{
pre = q;
q = q->next;
}
s->next = q;
pre->next = s;
}
printf("--创建成功--\n");
return p;
}
//一元多项式打印
void pri (polynomial p){
polynomial q;
int id = 1;
q = p->next;
printf("加法运算后结果为:\n");
while (q)
{
printf("第%d个结点:系数%f,指数%d\n",id,q->coef,q->expn);
q = q->next;
id++;
}
}
//一元多项式相加
polynomial addpolyn(polynomial pa,polynomial pb){
polynomial p1,p2,p3,q;
int sum;
p1 = pa->next;
p2 = pb->next;
p3 = pa;
while (p1&&p2)
{
if (p1->expn==p2->expn)
{
sum = p1->coef+p2->coef;
if (sum)
{
p1->coef = sum;
p3->next = p1;
p3 = p1;
p1 = p1->next;
q = p2;
p2 = p2->next;
free(q);
}else{
q = p1;
p1 = p1->next;
free(q);
q = p2;
p2 = p2->next;
free(q);
}
}else{
if (p1->expn<=p2->expn)
{
p3->next = p1;
p3 = p1;
p1 = p1->next;
}else{
p3->next = p2;
p3 = p2;
p2 = p2->next;
}
}
}
p3->next = p1?p1:p2;
free(pb);
return pa;
}
main(){
int m;
polynomial pa,pb,pc;
printf("==========创建一元多项式==========\n");
printf("创建A项数");scanf("%d",&m);
pa = createpolyn(pa,m);
printf("创建B项数");scanf("%d",&m);
pb = createpolyn(pb,m);
printf("==========一元多项式相加==========\n");
pc = addpolyn(pa,pb);
pri(pc);
printf("==========END==========");
}
小结
循环链表是一种特殊类型的链表,它的最后一个节点的指针域指向第一个节点,形成一个循环。循环链表的特点包括循环性、灵活性、内存效率高,但随机访问性能较差。
循环链表的基本运算包括创建循环链表、插入节点、删除节点、遍历循环链表、查找节点和修改节点值。这些基本运算可以通过遍历和操作循环链表的节点来实现。需要注意的是,在处理循环链表时,需要特别注意循环的终止条件,以避免陷入无限循环。
循环链表在某些场景下可以更方便地处理循环相关的问题,例如循环队列的实现。但在其他场景下,可能会使用其他类型的链表,例如单向链表、双向链表等。