一、链表的再认识(带起源结点)
1.起源结点
首结点的前驱结点即为起源结点,起源结点出现的目的是为了更方便地操作链表,其数据域可用来存放有效结点长度。
从我个人的角度出发,起源结点是链表的发源地,是链表生命的开始,孕育了链表后续的一切,是链表有效结点之母、之父,见证了链表全面的、联系的、运动的、有矛盾的、从无到有的变化过程。万分悲痛的是,它是无性繁殖,且每个后代只能生育一个后代。
什么鬼东西?胡说八道!
通俗来讲,链表的一切操作都要从起源结点出发,通过起源结点方可追踪到链表后续所有的有效结点。
2.起源指针
指向起源结点的指针,记录起源结点的位置,告诉我们起源结点在什么地方。
3.首指针
指向第一个有效结点的指针,记录首结点的位置,告诉我们首结点在什么地方。
4.尾指针
指向最后一个有效结点的指针,记录尾结点的位置,告诉我们尾结点在什么地方。
5.首结点
第一个有效结点,起源结点孕育出的第一个后代。
6.尾结点
最后一个有效结点,链表运动的停滞期,将来或倒退,或前进。
7.链表的下标
虽然链表从物理层面来讲是没有下标的,但是我们可以从逻辑上为链表赋予下标。链表的下标和数组的下标相同,从0开始记数,依次累加,起源结点下标为0,首结点下标为1,第二个结点下标为2,第三个结点下标为3,,,尾结点下标为●(你猜?)。
数组和链表下标的不同之处在于:数组有效结点可从0或1号下标开始存储,链表有效结点只能从1号下标开始存储。由此可知,链表的有效结点操作下标position范围为 1<=position<=●。
二、单向循环链表的认识
1.单向循环链表
尾结点的后继结点为起源结点的单向链表,形成一个环,即为单向循环链表。
从我的个人角度来理解,从生命之初,走向生命的终结,再从生命的终结走向生命之初,如此往复,生生不息。
2.起源结点、尾结点
在单向循环链表中,对有效结点的操作均是从尾结点开始,由尾结点回到起源结点。
尾结点不同于起源结点,起源结点在链表操作的过程中,整体是固定不变的;而尾结点在链表操作中变化颇多,
如:给单向循环链表追加结点后,尾结点就不在是原来的尾结点了;给单向循环链表删除尾结点后,尾结点亦不在是原来的尾结点了。
从我的个人角度来理解,起源结点—生命之初,尽管一路走来,尝尽了岁月的辛酸苦楚(增删改查),走向生命的终结(尾结点),但一直记得来时的路,不忘它的初心,不忘它的根。走遍世界,就是为了找到一条走回内心的路(起源结点)。
三、单向循环链表运行效果图
1.单向循环链表操作菜单
2.在未创建单向循环链表的情况下进行操作
(1)为单向循环链表排序
(2)释放单向循环链表
(3)逆转单向循环链表
(4)为单向循环链表追加结点
(5)为单向循环链表插入结点
(6)为单向循环链表删除结点
(7)为单向循环链表修改结点
(8)按结点下标取结点的值
(9)按结点值取结点下标
(10)退出
3.预期的运行
(1)创建单向循环链表
输入数字1进入单向循环链表的创建,再输入任意正整数确定结点的个数,最好小点,不然会很累人的,最后依次输入每个结点的值。
单向循环链表创建完成后,操作菜单下方呈现单向循环链表的长度,以及每个有效结点的值(后文中均简称为单向循环链表的数据显示、数据显示)。
(2)销毁单向循环链表
从起源结点开始,再首结点,第二个结点,第三个结点,,,尾结点依次释放。
单向循环链表销毁后,重新进入操作菜单,等待输入数字操作符。
(3)逆转单向循环链表
单向循环链表进行逆转后,输出反馈信息,并对其进行一次遍历,与单向循环链表的数据显示形成鲜明对比。
按任意键继续后,单向循环链表的数据显示已经呈现为逆转后的结果。
(4)为单向循环链表追加结点
结点追加完成后,对单向循环链表进行一次遍历,与其数据显示进行直接对照。
在按任意键继续后,单向循环链表的长度,结点变化均在其数据显示中体现出来。
(5)为单向循环链表删除结点
输入有效结点下标position(1<=position<=●),删除对应的结点。
①删除首结点操作
②首结点删除后的数据显示
③删除尾结点操作
④尾结点删除后的数据显示
(6)为双向循环链表插入结点
输入新结点要插入的下标position(1<=position<=●),结点的值value,进行插入结点操作。
①插入结点操作
②结点插入后的数据显示
(7)为单向循环链表修改结点
输入有效结点的下标position(1<=position<=●), 结点的值,进行结点修改操作。
①修改结点操作
②结点修改后的数据显示
(8)按结点下标取结点值
输入有效结点的下标,返回对应的结点值。
(9)按结点值取结点下标
输入有效结点的值,返回对应的结点下标
(10)为单向循环链表排序
①冒泡排序法,排序完成后,对其遍历一次
②排序后的数据显示
(11)退出
在链表已经创建,并存在多个结点的情况下,进行退出。先释放起源结点,再从首结点,,,尾结点依次进行释放,最后退出。
(12)在单向循环链表已创建,并已有多个结点时,再创建一次单向循环链表
4.错误输入下的运行
(1)创建单向循环链表时,输入小于等于零的数
(2)插入结点时,输入无效下标
(3)删除结点时,输入无效下标
(4)修改结点时,输入无效下标
(5)按有效结点下标取结点值时,输入无效下标
(6)按有效结点值取结点下标,输入结点值无效
5.单向循环链表为空的情况下的操作
单向循环链表为空,就是只剩起源结点一个结点,且起源结点的指针域指向自己。
(1)创建新的单向循环链表
先释放原先的起源结点,再创建新的单向循环链表。
(2)为单向循环链表排序
(3)销毁单向循环链表
释放起源结点,即已销毁单向循环链表
(4)逆转单向循环链表
(5)追加新结点
①输入新结点的值,创建新结点,先与尾结点牵链,再与起源结点牵链
②追加结点后数据显示
(6)插入新结点
(7)删除结点
(8)修改结点
(9)按有效结点下标取其值
(10)按值取下标
(11)退出
先释放空表的起源结点,再退出。
四、注解主要代码
1.CircularLinkedList.h
#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
#define status int
#define YES 1
#define NO -1
typedef struct node
{
int data;
struct node* next;
}*NodePointer, Node;
/*
单向循环链表的结点结构体
主要成员:
存放结点数据的整形变量 [数据的类型可随需要进行更换]
存放其后继结点的指针变量
*/
NodePointer initializeCircularLinkedList();
/*
初始化函数,创建单向循环链表的起源结点,返回起源结点指针。
*/
NodePointer createCircularLinkedList(NodePointer originalPointer,int length);
/*
创建单向循环链表函数,向函数形参传入起源结点指针、所需长度,依次创建后续有效结点,
返回尾结点指针。
*/
void manifestForCircularLinkedList(NodePointer rearPointer);
/*
遍历单向循环链表函数,向函数形参传入尾结点指针,输出单向循环链表的所有有效结点的数据。
*/
void appendForCircularLinkedList(NodePointer* rearPointerPointer, int data);
/*
追加结点函数,
向函数形参传入尾结点指针的指针[即尾结点的二重指针]、所追加的结点数据,完成追加结点操作。
这里解释下为什么要传入尾结点的二重指针:
单向循环链表的有效结点操作都是从尾结点开始操作,追加新结点后,
那么这个新结点是不是就成为单向循环链表当下的尾结点?
若将尾结点指针传入形参,当然可以完成追加结点操作,
可该函数以外的尾结点指针还是原先的尾结点指针,没有产生相应的改变。
其它函数的操作依旧是从原先的尾结点指针开始操作,无法得到预期的操作结果,
故传入尾结点的二重指针。
结点追加完成后,通过尾结点的二重指针改动函数外部的尾结点指针。
如果你认认真真看三遍都看不懂,不是你的问题,是我的问题,我没有讲清楚,欢迎您的指正和建议!
*/
status insertForCircularLinkedList(NodePointer rearPointer,int position,int data);
/*
插入结点函数,向函数形参传入尾结点指针、待插入结点的下标、待插入结点的数据,
返回结点插入后的状态值”YES or NO“。
若单向循环链表为空,则返回NO;
若输入下标无效,返回NO;
以上判断跳过之后,进行插入结点操作,插入完成后,返回YES。
*/
status deleteForCircularLinkedList(NodePointer* rearPointerPointer,int position);
/*
删除结点函数,向函数形参传入尾结点二重指针、待删除结点的下标,
返回结点删除后的状态值”YES or NO“。
若单向循环链表为空,则返回NO;
若输入下标无效,返回NO;
以上判断跳过之后,进行结点删除操作,结点删除后,返回YES。
为什么这里又要传入尾结点的二重指针呢?
若删除的结点刚好是尾结点,
那么该函数以外的尾结点指针是不是也要产生相应的变动呢?
*/
status modifyForCircularLinkedList(NodePointer rearPointer,int position,int data);
/*
修改结点数据函数,向函数形参传入尾结点指针、待修改结点的下标,修改的目标数据
返回结点修改后的状态值”YES or NO“。
若单向循环链表为空,则返回NO;
若输入下标无效,返回NO;
以上判断跳过之后,进行结点数据修改操作,结点数据修改完成后,返回YES。
*/
status IsCircularLinkedListEmpty(NodePointer rearPointer);
/*
判断单向循环链表是否为空函数,向函数形参传入 尾结点指针,
返回判断后的状态值”YES or NO“。
若尾结点的后继结点就是它自己,那么单向循环链表为空,返回YES,
否则返回NO。
*/
status inverseForCircularLinkedList(NodePointer rearPointer);
/*
逆转单向循环链表结点函数,向函数形参传入尾结点指针,
返回逆转后的状态值”YES or NO“。
若单向循环链表为空,则返回NO。
否则,进行逆转操作,逆转完成后,返回YES。
*/
status sortForCircularLinkedList(NodePointer rearPointer);
/*
为单向循环链表结点排序函数,向函数形参传入尾结点指针,
返回排序后的状态值”YES or NO“。
若单向循环链表为空,则返回NO,
否则,进行排序操作,排序完成后,返回YES。
*/
NodePointer getNodeForCircularLinkedList(NodePointer rearPointer, int position);
/*
按结点下标获取结点函数,向函数形参传入尾结点指针、结点下标,
返回目标结点指针。
若单向循环链表为空,则返回NULL;
若输入结点下标无效,则返回NULL;
跳过上述判断后,返回目标结点指针。
*/
status locateNodeForCircularLinkedList(NodePointer rearPointer,int data,int* position);
/*
按结点数据定位结点下标函数,向函数形参传入尾结点指针、结点数据、下标变量的指针
返回定位结点后的状态值”YES or NO“。
若单向循环链表为空,则下标变量赋值为-1,返回NO。
若结点数据定位到,则下标变量赋值为结点的下标,返回YES,
否则,则下标变量赋值为-1,返回NO。
*/
void clearForCircularLinkedList(NodePointer* rearPointerPointer);
/*
销毁单向循环链表函数,向函数形参传入尾结点的二重指针,完成销毁操作。
若传入的尾结点二重指针为NULL,则直接返回,不再执行后续操作。
若单向循环链表为空,则释放其起源结点,即完成销毁操作。
若单向循环链表不为空,先释放起源结点,
再首结点,第二个结点,,,尾结点,
完成销毁操作。
*/
2.CircularLinkedList.c
#include"CircularLinkedList.h"
NodePointer initializeCircularLinkedList()
{
NodePointer originalPointer = (NodePointer)malloc(sizeof(Node));//创建起源结点,将其指针保存到结点指针变量
if (originalPointer == NULL)//若起源指针变量为NULL,则堆内存分配失败,直接退出。
{
printf("initializeCircularLinkedList:\tOrigin Node Was Failed To Allocate Memory !\n");
exit(-1);
}
originalPointer->data = 0; //初始化起源结点的数据域
originalPointer->next = NULL;//初始化起源结点的指针域
return originalPointer;
}
NodePointer createCircularLinkedList(NodePointer originalPointer, int length)
{
NodePointer rearPointer = originalPointer;//传入起源指针,从逻辑上当作尾指针处理
NodePointer newbornPointer = NULL;//创建新结点指针变量并初始化为NULL
originalPointer->data = length;//起源结点的数据域用来存放有效结点的个数
int data;
for (int i = 0; i < length; i++)
{
newbornPointer = (NodePointer)malloc(sizeof(Node));//创建新结点,将其指针保存到结点指针变量
if (newbornPointer == NULL)//若新结点指针变量为空,则表明堆内存分配失败,直接退出
{
printf("createCircularLinkedList:\tNewborn Node Was Failed To Allocate Memory !\n");
exit(-1);
}
printf("Node\t%d:\t", i + 1);
scanf("%d", &data);//为新结点录入数据
newbornPointer->data = data;//将数据存入新结点数据域
newbornPointer->next = NULL;//新结点的指针域赋值为NULL
rearPointer->next = newbornPointer;//尾结点的指针域指向新结点
rearPointer = newbornPointer;//此时此刻的尾结点断然不是原来的尾结点了,而是新结点
}
rearPointer->next = originalPointer;//尾结点的指针域指向起源结点指针,完成单向循环链表的创建
return rearPointer;
}
void manifestForCircularLinkedList(NodePointer rearPointer)
{
if (IsCircularLinkedListEmpty(rearPointer)==YES)
{
printf("The CircularLinkedList Is Empty.\tManifesting was Denied!\n");
return;
}
NodePointer originalPointer = rearPointer->next;//由尾结点的指针域获取起源结点指针
NodePointer temporaryPointer = originalPointer;//创建临时的结点指针变量,赋值为起源指针
printf("[\t");
/*
单向循环链表从起源结点向后遍历,若当前结点的指针域指向起源结点,表明当前结点即为尾结点,结束循环。
循环体中的结点均是由其前驱结点来表示的,略微烧脑。
当前结点 用其指针域表示后继结点
起源结点 首结点
首结点 第二个结点
第二个结点 第三个结点
,,,
倒数第三个结点 倒数第二个结点
倒数第二个结点 尾结点
尾结点 首结点
画图会更好理解,可这些图已经存在于书籍和网络当中,便不再搬运和制作了。
*/
for (; temporaryPointer->next!= originalPointer; temporaryPointer= temporaryPointer->next)
{
if (temporaryPointer->next->next!= originalPointer)
printf("%d,\t", temporaryPointer->next->data);
else
printf("%d", temporaryPointer->next->data);
}
printf("\t]\n");
}
void appendForCircularLinkedList(NodePointer* rearPointerPointer, int data)
{
NodePointer originalPointer =( *rearPointerPointer)->next;//由尾指针获取起源指针
NodePointer newbornPointer = (NodePointer)malloc(sizeof(Node));//创建新结点,将其指针保存到结点指针变量
if (newbornPointer == NULL)//若新结点指针变量为空,则表明堆内存分配失败,直接退出
{
printf("appendForCircularLinkedList:\tNewborn node was failed to allocate memory\n");
exit(-1);
}
newbornPointer->data = data;//为新结点数据域赋值
newbornPointer->next = originalPointer;//新结点的指针域指向起源结点
(*rearPointerPointer)->next = newbornPointer;//此时的新结点已成为尾结点了
*rearPointerPointer = newbornPointer;//新结点追加完成后,将尾指针变量赋值为新结点指针
++originalPointer->data;//起源结点数据域加1,为什么加1?起源结点数据域存放有效结点个数
}
NodePointer getNodeForCircularLinkedList(NodePointer rearPointer, int position)
{
if (IsCircularLinkedListEmpty(rearPointer)==YES)//若单向循环链表为空,返回NULL
{
printf("The CircularLinkedList Is Empty!\n");
return NULL;
}
NodePointer originalPointer = rearPointer->next;//由尾结点指针域定位到起源结点
NodePointer mantisPointer = rearPointer->next;
int i;
for (i = 1; i < position && mantisPointer->next != originalPointer; i++, mantisPointer = mantisPointer->next);
/*
上述循环需要好好思考一番
倘若是傻瓜式循环“for (i = 1; i < position ; i++);”,循环结束时,i=position
上述循环中,还带了单向循环链表遍历,排除异常情况,
起源结点下标为0,首结点下标为1,,,循环结束时,已遍历到第position-1个结点。
没错,我们就是要遍历前position-1个结点,看看第position-1个结点是否为尾结点。
若循环提前结束,要么i>position;要么单向循环链表已遍历到尾结点
若输入的position<=0,又i=1,则i>position,结束循环 下标向左越界
若输入的position大于尾结点下标,则单向循环链表遍历到尾结点,结束循环 下标向右越界
*/
if (i > position || mantisPointer->next == originalPointer)
{
printf("INVALID POSITION!\n");
return NULL;
}
return mantisPointer->next;//返回第position个结点
}
status insertForCircularLinkedList(NodePointer rearPointer,int position,int data)
{
if (getNodeForCircularLinkedList(rearPointer, position) == NULL)
{
printf("Inserting Node Is Unable To Execute !\n");
return NO;
}
NodePointer originalPointer = rearPointer->next;
for (int i = 0; i < position - 1; i++, originalPointer = originalPointer->next);
NodePointer newbornPointer = (NodePointer)malloc(sizeof(Node));
if (newbornPointer == NULL)
{
printf("insertForCircularLinkedList:\tNewborn Node Was Failed To Allocate Memory !\n");
exit(-1);
}
newbornPointer-> data = data;
newbornPointer->next = originalPointer->next;
originalPointer->next = newbornPointer;
rearPointer->next->data++;
printf("The target node %d has been inserted into CircularLinkedList completely!\n", data);
return YES;
}
status deleteForCircularLinkedList(NodePointer* rearPointerPointer, int position)
{
NodePointer aimPointer = getNodeForCircularLinkedList(*rearPointerPointer, position);//获取第position个目标结点
if (aimPointer == NULL)
{
printf("Deleting Node Is Unable To Execute !\n");
return NO;
}
int data;
NodePointer originalPointer = (*rearPointerPointer)->next;
originalPointer->data = originalPointer->data - 1;//起源结点数据域减1,为什么减1?起源结点数据域存放有效结点个数
NodePointer fleaPointer =( *rearPointerPointer)->next;
for (int i = 0; i < position - 1; i++, fleaPointer = fleaPointer->next);//遍历到第position-1个结点
if (aimPointer->next == originalPointer)//若待删除的目标结点是尾结点,
(*rearPointerPointer) = fleaPointer;//则尾指针指向目标结点的前驱结点,即第position-1个结点
fleaPointer->next = aimPointer->next;//目标结点与其前驱结点、后继结点断链
data = aimPointer->data;
free(aimPointer);//释放目标结点
printf("The target node %d has been released completely!\n", data);
return YES;
}
status modifyForCircularLinkedList(NodePointer rearPointer,int position,int data)
{
NodePointer targetPointer = getNodeForCircularLinkedList(rearPointer, position);
if (targetPointer == NULL)
{
printf("The Node Modification Is Unable To Perform !\n");
return NO;
}
int inherentdata=targetPointer->data;
targetPointer->data = data;
printf("The inherent node %d has been modified completely!\n", inherentdata);
return YES;
}
status IsCircularLinkedListEmpty(NodePointer rearPointer)
{
if (rearPointer->next==rearPointer)
return YES;
return NO;
/*
尾结点的指针域指向尾结点,则表明单向循环链表中只有一个结点,
这个结点就是尾结点,这个结点就是起源结点,起源结点和尾结点都它。
在这种情况下,判定单向循环链表为空。
*/
}
status inverseForCircularLinkedList(NodePointer rearPointer)
{
if (IsCircularLinkedListEmpty(rearPointer)==YES)
{
printf("The CircularLinkedList Is Empty.Inversion Is Unable To Perform !\n");
return NO;
}
NodePointer originalPointer = rearPointer->next;
NodePointer fleaPointer = NULL;
int end = originalPointer->data;//存储单向循环链表的长度—尾结点的下标
int center = end / 2;
int temp;
/*
从尾结点向后倒[单向循环链表可倒不了],从起源结点向前进,
首结点和尾结点、第二个结点和倒数第二个结点,,,依次进行数据交换
*/
while(end>center)//尾结点下标到达中心结点下标后,退出循环
{
//----------------------------------------------------------------------------------------
fleaPointer = rearPointer->next;//每次循环,结点指针变量都赋值为起源结点指针
for (int i = 0; i < end; i++)
{
fleaPointer = fleaPointer->next;//从起源结点向前进,进到待交换的目标结点
}
end = end - 1;//退到其前驱结点
//----------------------------------------------------------------------------------------
originalPointer = originalPointer->next;
temp = originalPointer->data;
originalPointer->data = fleaPointer->data;
fleaPointer->data = temp;
}
printf("The CircularLinkedList has been inversed completely.\n");
return YES;
}
status sortForCircularLinkedList(NodePointer rearPointer)//bubble sort
{
if (IsCircularLinkedListEmpty(rearPointer)==YES)
{
printf("The CircularLinkedList Is Empty.Sort Is Unable To Perform !\n");
return NO;
}
NodePointer originalPointer = rearPointer->next;
NodePointer mantisPointer= NULL;
int length = originalPointer->data;
int end = length - 1;
int temp;
for (int i = 0; i < end; i++)
{
mantisPointer = originalPointer->next;
for (int j = 0; j < length-1-i; j++)
{
if (mantisPointer->data > mantisPointer->next->data)
{
temp = mantisPointer->data;
mantisPointer->data = mantisPointer->next->data;
mantisPointer->next->data = temp;
}
mantisPointer = mantisPointer->next;
}
}
return YES;
}
status locateNodeForCircularLinkedList(NodePointer rearPointer,int data,int* position)
{
*position = -1;
if (IsCircularLinkedListEmpty(rearPointer)==YES)
{
printf("The CircularLinkedList Is Empty.\tThe CircularLinkedList Unable To Locate Node !\n");
return NO;
}
NodePointer originalPointer = rearPointer->next;
NodePointer fleaPointer = rearPointer->next->next;
int length = originalPointer->data;
for (int i = 0; i < length && fleaPointer!=originalPointer; i++)
{
if (fleaPointer->data==data)
{
*position = i + 1;
return YES;
}
fleaPointer = fleaPointer->next;
}
printf("The Node Doesn't Exist !\n");
return NO;
}
void clearForCircularLinkedList(NodePointer* rearPointerPointer)
{
if ((*rearPointerPointer)==NULL)//若尾指针变量为空,直接返回
return;
if (IsCircularLinkedListEmpty(*(rearPointerPointer))==YES)//若单向循环链表为空
{
free(*rearPointerPointer);//释放起源结点,即销毁了单向循环链表
printf("The \toriginal node\thas been released completely !\n");
*rearPointerPointer = NULL;//将尾指针变量赋值为NULL
return;//返回,后续不再执行
}
NodePointer originalPointer = (*rearPointerPointer)->next;//由尾结点定位起源结点
NodePointer mantisPointer = (*rearPointerPointer)->next->next;//从尾结点定位到首结点
NodePointer fleaPointer = NULL;
int data;
free(originalPointer);//起源结点最先释放
printf("The \toriginal node\thas been released completely !\n");
while (mantisPointer !=originalPointer)//从首结点向后遍历,回到起源结点立即结束循环
{
fleaPointer = mantisPointer;//将待释放的目标结点保存起来
mantisPointer = mantisPointer->next;//从目标结点定位到它的后继结点
data = fleaPointer->data;
free(fleaPointer);//释放目标结点
printf("The node\t%d\thas been released completely !\n", data);
}
*rearPointerPointer = NULL;//将尾指针变量赋值为NULL
}
五、一字一句的纯代码
1.CircularLinkedList.h
#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
#define status int
#define YES 1
#define NO -1
typedef struct node
{
int data;
struct node* next;
}*NodePointer, Node;
NodePointer initializeCircularLinkedList();
NodePointer createCircularLinkedList(NodePointer originalPointer,int length);
void manifestForCircularLinkedList(NodePointer rearPointer);
void appendForCircularLinkedList(NodePointer* rearPointerPointer, int data);
status insertForCircularLinkedList(NodePointer rearPointer,int position,int data);
status deleteForCircularLinkedList(NodePointer* rearPointerPointer,int position);
status modifyForCircularLinkedList(NodePointer rearPointer,int position,int data);
status IsCircularLinkedListEmpty(NodePointer rearPointer);
status inverseForCircularLinkedList(NodePointer rearPointer);
status sortForCircularLinkedList(NodePointer rearPointer);
NodePointer getNodeForCircularLinkedList(NodePointer rearPointer, int position);
status locateNodeForCircularLinkedList(NodePointer rearPointer,int data,int* position);
void clearForCircularLinkedList(NodePointer* rearPointerPointer);
2.CircularLinkedList.c
#include"CircularLinkedList.h"
NodePointer initializeCircularLinkedList()
{
NodePointer originalPointer = (NodePointer)malloc(sizeof(Node));
if (originalPointer == NULL)
{
printf("initializeCircularLinkedList:\tOrigin Node Was Failed To Allocate Memory !\n");
exit(-1);
}
originalPointer->data = 0;
originalPointer->next = NULL;
return originalPointer;
}
NodePointer createCircularLinkedList(NodePointer originalPointer, int length)
{
NodePointer rearPointer = originalPointer;
NodePointer newbornPointer = NULL;
originalPointer->data = length;
int data;
for (int i = 0; i < length; i++)
{
newbornPointer = (NodePointer)malloc(sizeof(Node));
if (newbornPointer == NULL)
{
printf("createCircularLinkedList:\tNewborn Node Was Failed To Allocate Memory !\n");
exit(-1);
}
printf("Node\t%d:\t", i + 1);
scanf("%d", &data);
newbornPointer->data = data;
newbornPointer->next = NULL;
rearPointer->next = newbornPointer;
rearPointer = newbornPointer;
}
rearPointer->next = originalPointer;
return rearPointer;
}
void manifestForCircularLinkedList(NodePointer rearPointer)
{
if (IsCircularLinkedListEmpty(rearPointer)==YES==YES)
{
printf("The CircularLinkedList Is Empty.\tManifesting was Denied!\n");
return;
}
NodePointer originalPointer = rearPointer->next;
NodePointer temporaryPointer = originalPointer;;
printf("[\t");
for (; temporaryPointer->next!= originalPointer; temporaryPointer= temporaryPointer->next)
{
if (temporaryPointer->next->next!= originalPointer)
printf("%d,\t", temporaryPointer->next->data);
else
printf("%d", temporaryPointer->next->data);
}
printf("\t]\n");
}
void appendForCircularLinkedList(NodePointer* rearPointerPointer, int data)
{
NodePointer originalPointer =( *rearPointerPointer)->next;
NodePointer newbornPointer = (NodePointer)malloc(sizeof(Node));
if (newbornPointer == NULL)
{
printf("appendForCircularLinkedList:\tNewborn node was failed to allocate memory\n");
exit(-1);
}
newbornPointer->data = data;
newbornPointer->next = originalPointer;
(*rearPointerPointer)->next = newbornPointer;
*rearPointerPointer = newbornPointer;
++originalPointer->data;
}
NodePointer getNodeForCircularLinkedList(NodePointer rearPointer, int position)
{
if (IsCircularLinkedListEmpty(rearPointer)==YES)
{
printf("The CircularLinkedList Is Empty!\n");
return NULL;
}
NodePointer originalPointer = rearPointer->next;
NodePointer mantisPointer = rearPointer->next;
int i;
for (i = 1; i < position && mantisPointer->next != originalPointer; i++, mantisPointer = mantisPointer->next);
if (i > position || mantisPointer->next == originalPointer)
{
printf("INVALID POSITION!\n");
return NULL;
}
return mantisPointer->next;
}
status insertForCircularLinkedList(NodePointer rearPointer,int position,int data)
{
if (getNodeForCircularLinkedList(rearPointer, position) == NULL)
{
printf("Inserting Node Is Unable To Execute !\n");
return NO;
}
NodePointer originalPointer = rearPointer->next;
for (int i = 0; i < position - 1; i++, originalPointer = originalPointer->next);
NodePointer newbornPointer = (NodePointer)malloc(sizeof(Node));
if (newbornPointer == NULL)
{
printf("insertForCircularLinkedList:\tNewborn Node Was Failed To Allocate Memory !\n");
exit(-1);
}
newbornPointer-> data = data;
newbornPointer->next = originalPointer->next;
originalPointer->next = newbornPointer;
rearPointer->next->data++;
printf("The target node %d has been inserted into CircularLinkedList completely!\n", data);
return YES;
}
status deleteForCircularLinkedList(NodePointer* rearPointerPointer, int position)
{
NodePointer aimPointer = getNodeForCircularLinkedList(*rearPointerPointer, position);
if (aimPointer == NULL)
{
printf("Deleting Node Is Unable To Execute !\n");
return NO;
}
int data;
NodePointer originalPointer = (*rearPointerPointer)->next;
originalPointer->data = originalPointer->data - 1;
NodePointer fleaPointer =( *rearPointerPointer)->next;
for (int i = 0; i < position - 1; i++, fleaPointer = fleaPointer->next);
if (aimPointer->next == originalPointer)
(*rearPointerPointer) = fleaPointer;
fleaPointer->next = aimPointer->next;
data = aimPointer->data;
free(aimPointer);
printf("The target node %d has been released completely!\n", data);
return YES;
}
status modifyForCircularLinkedList(NodePointer rearPointer,int position,int data)
{
NodePointer targetPointer = getNodeForCircularLinkedList(rearPointer, position);
if (targetPointer == NULL)
{
printf("The Node Modification Is Unable To Perform !\n");
return NO;
}
int inherentdata=targetPointer->data;
targetPointer->data = data;
printf("The inherent node %d has been modified completely!\n", inherentdata);
return YES;
}
status IsCircularLinkedListEmpty(NodePointer rearPointer)
{
if (rearPointer->next==rearPointer)
return YES;
return NO;
}
status inverseForCircularLinkedList(NodePointer rearPointer)
{
if (IsCircularLinkedListEmpty(rearPointer)==YES)
{
printf("The CircularLinkedList Is Empty.Inversion Is Unable To Perform !\n");
return NO;
}
NodePointer originalPointer = rearPointer->next;
NodePointer fleaPointer = NULL;
int end = originalPointer->data;
int center = end / 2;
int temp;
while(end>center)
{
fleaPointer = rearPointer->next;
for (int i = 0; i < end; i++)
{
fleaPointer = fleaPointer->next;
}
end = end - 1;
originalPointer = originalPointer->next;
temp = originalPointer->data;
originalPointer->data = fleaPointer->data;
fleaPointer->data = temp;
}
printf("The CircularLinkedList has been inversed completely.\n");
return YES;
}
status sortForCircularLinkedList(NodePointer rearPointer)//bubble sort
{
if (IsCircularLinkedListEmpty(rearPointer)==YES)
{
printf("The CircularLinkedList Is Empty.Sort Is Unable To Perform !\n");
return NO;
}
NodePointer originalPointer = rearPointer->next;
NodePointer mantisPointer= NULL;
int length = originalPointer->data;
int end = length - 1;
int temp;
for (int i = 0; i < end; i++)
{
mantisPointer = originalPointer->next;
for (int j = 0; j < length-1-i; j++)
{
if (mantisPointer->data > mantisPointer->next->data)
{
temp = mantisPointer->data;
mantisPointer->data = mantisPointer->next->data;
mantisPointer->next->data = temp;
}
mantisPointer = mantisPointer->next;
}
}
return YES;
}
status locateNodeForCircularLinkedList(NodePointer rearPointer,int data,int* position)
{
*position = -1;
if (IsCircularLinkedListEmpty(rearPointer)==YES)
{
printf("The CircularLinkedList Is Empty.\tThe CircularLinkedList Unable To Locate Node !\n");
return NO;
}
NodePointer originalPointer = rearPointer->next;
NodePointer fleaPointer = rearPointer->next->next;
int length = originalPointer->data;
for (int i = 0; i < length && fleaPointer!=originalPointer; i++)
{
if (fleaPointer->data==data)
{
*position = i + 1;
return YES;
}
fleaPointer = fleaPointer->next;
}
printf("The Node Doesn't Exist !\n");
return NO;
}
void clearForCircularLinkedList(NodePointer* rearPointerPointer)
{
if ((*rearPointerPointer)==NULL)
return;
if (IsCircularLinkedListEmpty(*(rearPointerPointer))==YES)
{
free(*rearPointerPointer);
printf("The \toriginal node\thas been released completely !\n");
*rearPointerPointer = NULL;
return;
}
NodePointer originalPointer = (*rearPointerPointer)->next;
NodePointer mantisPointer = (*rearPointerPointer)->next->next;
NodePointer fleaPointer = NULL;
int data;
free(originalPointer);
printf("The \toriginal node\thas been released completely !\n");
while (mantisPointer !=originalPointer)
{
fleaPointer = mantisPointer;
mantisPointer = mantisPointer->next;
data = fleaPointer->data;
free(fleaPointer);
printf("The node\t%d\thas been released completely !\n", data);
}
*rearPointerPointer = NULL;
}
3.main.c
#include"CircularLinkedList.h"
#include"Tools.h"
void main()
{
char* operatingMenu[] = { "Circular Linked List",
"1.create","2.sort","3.clear","4.inverse",
"5.append node","6.insert node",
"7.delete node","8.modify node",
"9.get node","10.locate node",
"11.exit"};
int length, digit,data, position,state;
NodePointer rearPointer = NULL;
NodePointer originalPointer = NULL;
while (1)
{
system("cls");
menu(operatingMenu, sizeof(operatingMenu) / sizeof(char*));
if (rearPointer != NULL && IsCircularLinkedListEmpty(rearPointer)==NO)
{
printf("Length:\t\%d", rearPointer->next->data);
printf("\t,\t");
printf("Data:\t");
manifestForCircularLinkedList(rearPointer);
}
inputData("\ntype in digit:\t", "%d", &digit);
if (digit < 1 || digit>11)
continue;
if (rearPointer == NULL && digit!=1 && digit!=11 )
{
printf("The Circular Linked List is required to create !\n");
system("pause");
continue;
}
switch (digit)
{
case 1:
clearForCircularLinkedList(&rearPointer);
inputData("The Length of Circular Linked List:\t", "%d", &length);
if (length <= 0)
break;
originalPointer=initializeCircularLinkedList();
rearPointer = createCircularLinkedList(originalPointer,length);
break;
case 2:
state = sortForCircularLinkedList(rearPointer);
state==YES? manifestForCircularLinkedList(rearPointer) : printf("check out and try again !\n");
break;
case 3:
clearForCircularLinkedList(&rearPointer);
break;
case 4:
state = inverseForCircularLinkedList(rearPointer);
state==YES? manifestForCircularLinkedList(rearPointer) : printf("check out and try again !\n");
break;
case 5:
inputData("DATA:\t", "%d", &data);
appendForCircularLinkedList(&rearPointer, data);
manifestForCircularLinkedList(rearPointer);
break;
case 6:
inputData("POSITION:\t", "%d", &position);
inputData("DATA:\t", "%d", &data);
state = insertForCircularLinkedList(rearPointer, position, data);
state==YES? manifestForCircularLinkedList(rearPointer) : printf("check out and try again !\n");
break;
case 7:
inputData("PISITION:\t", "%d", &position);
state = deleteForCircularLinkedList(&rearPointer, position);
state==YES? manifestForCircularLinkedList(rearPointer) : printf("check out and try again !\n");
break;
case 8:
inputData("PISITION:\t", "%d", &position);
inputData("DATA:\t", "%d", &data);
state = modifyForCircularLinkedList(rearPointer, position, data);
state==YES? manifestForCircularLinkedList(rearPointer) : printf("check out and try again !\n");
break;
case 9:
inputData("PISITION:\t", "%d", &position);
NodePointer targetPointer = getNodeForCircularLinkedList(rearPointer, position);
targetPointer == NULL ? printf("check out and try again !\n") : printf("DATA:\t%d\n", targetPointer->data);
break;
case 10:
inputData("DATA:\t", "%d", &data);
state = locateNodeForCircularLinkedList(rearPointer, data, &position);
state == NO ? printf("check out and try again !\n") : printf("POSITION:\t%d\n", position);
break;
case 11:
clearForCircularLinkedList(&rearPointer);
printf("You have already exited.\n");
system("pause");
exit(-1);
break;
}
system("pause");
}
}
4.Tools.h
#include<stdio.h>
#include<string.h>
#define SPAN 50
#define VerticalGap 1
void menu(char** menu, int length);
void duplicate(char* token, int amount);
void inputData(char* hint, char* type, void* data);
5.Tools.c
#include"Tools.h"
void menu(char** menu, int length)
{
duplicate("-", SPAN);
duplicate("\n", 1);
int gap;
for (int i = 0; i < length; i++)
{
printf("-");
gap = SPAN - strlen(*(menu + i)) - 2;
if (gap % 2 == 0)
duplicate(" ", gap / 2);
else
duplicate(" ", gap / 2 + 1);
printf("%s", menu[i]);
duplicate(" ", gap / 2);
printf("-");
duplicate("\n", VerticalGap);
}
duplicate("-", SPAN);
printf("\n");
}
void duplicate(char* token, int amount)
{
for (int i = 0; i < amount; i++)
{
printf("%s", token);
}
}
void inputData(char* hint, char* type, void* data)
{
printf("%s", hint);
scanf(type, data);
}
六、此时此刻的感受
因为上篇博客的细致,所以强迫症的我无法不再细致下去,要整洁,要条理,要正确 ,要耐心,要坚持。这篇博客很耗心力,也耗时间,若不是自己的强迫症,真心无法完成。
有这样一句话“凡有所学,皆成性格。”,我在写博客的路途中,突然也觉得自己的屋子比较乱,东西放得也不整齐,物件规整得也不对,不知道哪来的一股劲迫使着自己去收拾这一切,也许就像是那句话说的样子吧,你所学知识的特性,同时也会造就你在生活的性情。