线性表的链式存储-单向循环链表,认识的前进上升

一、链表的再认识(带起源结点)

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);
}


六、此时此刻的感受

因为上篇博客的细致,所以强迫症的我无法不再细致下去,要整洁,要条理,要正确 ,要耐心,要坚持。这篇博客很耗心力,也耗时间,若不是自己的强迫症,真心无法完成。
有这样一句话“凡有所学,皆成性格。”,我在写博客的路途中,突然也觉得自己的屋子比较乱,东西放得也不整齐,物件规整得也不对,不知道哪来的一股劲迫使着自己去收拾这一切,也许就像是那句话说的样子吧,你所学知识的特性,同时也会造就你在生活的性情。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值