【数据结构】单向循环链表的实现

不带头单向循环链表结构如下:
单向循环链表
其中,详细介绍不带头单向循环链表的排序功能的实现。
以以下链表为例:
在这里插入图片描述
第一步:
将该单向循环链表分成只有一个结点的单向循环链表p和由剩下结点组成的一个单向不循环链表q。
在这里插入图片描述
第二步:
将p指向q链表要比较的第一个结点,q用来保存下一个结点,prev用来保存要插入位置的前一个节点的位置,cur用来保存要插入位置的结点。
比较 1<2,并没有进入第二个while中,此时prev仍为NULL,故应该将结点头插进入该单向循环链表中,由于头插会改变头结点,而单向循环链表的尾结点会指向头结点,所以需要借助第三个循环找到尾结点,更新它所指向的头结点。
在这里插入图片描述
头插成功,重新置prev为NULL,cur指向头结点。
在这里插入图片描述
第三步:
由于 4>1 且 4>2,故cur由结点1->结点2->结点1,prev由NULL->结点1->结点2,此时cur再次指向头结点,第二个循环结束,所以结点4需要插入在最后一个结点和第一个结点之间,也就是尾插。
在这里插入图片描述
尾插成功,重新置prev为NULL,cur指向头结点。
在这里插入图片描述
第四步:
由于 3>1且3>2,故cur由结点1->结点2->结点4,prev由NULL->结点1->结点2,此时cur指向的结点4>当前p结点即结点3,所以第二个循环结束。将结点3插入在prev和cur之间。
在这里插入图片描述
插入成功,整个排序工作也就完成了。
在这里插入图片描述
具体实现的代码如下;

void SCListSort(SCList* phead)
{
	assert(phead != NULL);
	if (SCListLength(*phead) == 1 || SCListLength(*phead)== 0)
		return;
	SCListNode* p = *phead;
	SCListNode* q = (*phead)->next;
	p->next = *phead;
	//将该单向循环链表分成只有一个结点的单向循环链表p和由剩下结点组成的一个单向不循环链表q。
	SCListNode* node = q;
	while (node->next != *phead)
		node = node->next;
	node->next = NULL;

	SCListNode* cur = *phead;
	SCListNode* prev = NULL;
	//第一个循环,用以保存所需插入到已有序的单向循环链表中的结点。
	while (q != NULL)
	{
		p = q;
		q = q->next;

		while (cur != NULL && cur->data < p->data)//第二个循环,寻找所需插入结点的位置和其前一个位置
		{
			prev = cur;
			cur = cur->next;
			if (cur == *phead)
				break;
		}
		if (prev == NULL)//头插
		{
			SCListNode* last = *phead;
			//第三个循环,用以找到单向循环链表的尾结点,以更新其指向的头结点
			while (last->next != *phead)
				last = last->next;
			p->next = *phead;
			*phead = p;
			last->next = *phead;
		}
		else
		{
			prev->next = p;
			p->next = cur;
		}
		prev = NULL;
		cur = *phead;
	}
}

单向循环链表各个功能实现如下:

//sclist.h
#pragma once
#include"commen.h"

#define ElemType int
typedef struct SCListNode
{
	ElemType data;
	struct SCListNode* next;
}SCListNode;

typedef SCListNode* SCList;

void SCListInit(SCList* phead);
void SCListDestroy(SCList* phead);
void SCListShow(SCList phead);
void SCListPushBack(SCList* phead, ElemType x);
void SCListPushFront(SCList* phead, ElemType x);
void SCListPopBack(SCList* phead);
void SCListPopFront(SCList* phead);
size_t SCListLength(SCList phead);
SCListNode* SCListFind(SCList phead, ElemType key);
void SCListEraseByVal(SCList* phead, ElemType key);
void SCListSort(SCList* phead);
void SCListInsertByVal(SCList* phead, ElemType x);
ElemType SCListFront(SCList* phead);
ElemType SCListBack(SCList* phead);
void SCListEraseAll(SCList* phead, ElemType x);
void SCListClean(SCList* phead);
void SCListReverse(SCList* phead);
///
void SCListInit(SCList* phead)
{
	*phead = NULL;
}
void SCListShow(SCList phead)
{
	SCListNode* cur = phead;
	if (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
		while (cur != NULL && cur != phead)
		{
			printf("%d->", cur->data);
			cur = cur->next;
		}
	}
	printf("over\n");
}

void SCListPushBack(SCList* phead, ElemType x)
{
	assert(phead != NULL);
	SCListNode* node = (SCListNode*)malloc(sizeof(SCListNode));
	assert(node != NULL);
	node->data = x;
	SCListNode* cur = *phead;
	if (cur == NULL)//插入的结点是第一个结点
		*phead = node;
	else
	{
		while (cur->next != *phead)
			cur = cur->next;
		cur->next = node;
	}
	node->next = *phead;//最后一个结点指向头部
}
void SCListPushFront(SCList* phead, ElemType x)
{
	assert(phead != NULL);
	SCListNode* node = (SCListNode*)malloc(sizeof(SCListNode));
	node->data = x;
	SCListNode* last = *phead;
	if (*phead == NULL)//链表为空时进行头插
	{
		*phead = node;
		node->next = *phead;
	}
	else
	{
		//找到最后一个结点
		while (last->next != *phead)
			last = last->next;
		node->next = *phead;
		*phead = node;
		last->next = *phead;
	}
}
void SCListPopBack(SCList* phead)
{
	assert(phead != NULL);
	if (*phead == NULL)
		printf("当前链表为空,无法进行删除操作\n");
	else if (SCListLength(*phead) == 1)//只有一个结点
	{
		free(*phead);
		*phead = NULL;
	}
	else
	{
		SCListNode* cur = *phead;
		SCListNode* prev = NULL;
		while (cur->next != *phead)
		{
			prev = cur;
			cur = cur->next;
		}
		free(cur);
		cur = NULL;
		prev->next = *phead;
	}
}
void SCListPopFront(SCList* phead)
{
	assert(phead != NULL);
	if (*phead == NULL)
		printf("当前链表为空,无法进行删除操作\n");
	else if (SCListLength(*phead) == 1)
	{
		free(*phead);
		*phead = NULL;
	}
	else
	{
		SCListNode* cur = *phead;
		SCListNode* newhead = cur->next;
		while (cur->next != *phead)
			cur = cur->next;
		cur->next = newhead;
		free(*phead);
		*phead = newhead;
	}
}
size_t SCListLength(SCList phead)
{
	if (phead == NULL)
		return 0;
	size_t len = 1;
	SCListNode* cur = phead->next;
	while (cur != NULL && cur != phead)
	{
		cur = cur->next;
		++len;
	}
	return len;
}
void SCListDestroy(SCList* phead)
{
	assert(phead != NULL);
	SCListNode* cur = *phead;
	while (*phead != NULL)
	{
		SCListPopBack(phead);
	}
}
SCListNode* SCListFind(SCList phead, ElemType key)
{
	assert(phead != NULL);
	SCListNode* cur = phead;
	while (cur != NULL && cur->data != key)
	{
		cur = cur->next;
		if (cur->next == phead)
			return NULL;
	}
	return cur;
}
void SCListEraseByVal(SCList* phead, ElemType key)
{
	assert(phead != NULL);
	if (*phead == NULL)
		printf("该链表为空,无法进行删除操作\n");
	else if((*phead)->data == key)
	{
		SCListPopFront(phead);
	}
	else
	{
		SCListNode* cur = *phead;
		SCListNode* prev = NULL;
		while (cur->data != key)
		{
			if (cur->next == *phead)
			{
				printf("该链表中没有元素%d,无法进行删除操作\n", key);
				return;
			}
			prev = cur;
			cur = cur->next;
		}
		if (cur->next == *phead)
			SCListPopBack(phead);
		else
		{
			prev->next = cur->next;
			free(cur);
			cur = NULL;
		}
	}
}
ElemType SCListFront(SCList* phead)
{
	assert(phead != NULL);
	if (*phead == NULL)
		return -1;
	else
		return (*phead)->data;
}
ElemType SCListBack(SCList* phead)
{
	assert(phead != NULL);
	if (*phead == NULL)
		return -1;
	else
	{
		SCListNode* cur = *phead;
		while (cur->next != *phead)
			cur = cur->next;
		return cur->data;
	}
}
void SCListSort(SCList* phead)
{
	assert(phead != NULL);
	if (SCListLength(*phead) == 1 || SCListLength(*phead)== 0)
		return;
	SCListNode* p = *phead;
	SCListNode* q = (*phead)->next;
	p->next = *phead;
//将该单向循环链表分成只有一个结点的单向循环链表p和由剩下结点组成的一个单向不循环链表q。
	SCListNode* node = q;
	while (node->next != *phead)
		node = node->next;
	node->next = NULL;

	SCListNode* cur = *phead;
	SCListNode* prev = NULL;
	while (q != NULL)//第一个循环,用以保存所需插入到已有序的单向循环链表中的结点。
	{
		p = q;
		q = q->next;

		while (cur != NULL && cur->data < p->data)//第二个循环,寻找所需插入结点的位置和其前一个位置
		{
			prev = cur;
			cur = cur->next;
			if (cur == *phead)
				break;
		}
		if (prev == NULL)//头插
		{
			SCListNode* last = *phead;
			while (last->next != *phead)//第三个循环,用以找到单向循环链表的尾结点,以更新其指向的头结点
				last = last->next;
			p->next = *phead;
			*phead = p;
			last->next = *phead;
		}
		else
		{
			prev->next = p;
			p->next = cur;
		}
		prev = NULL;
		cur = *phead;
	}
}
void SCListInsertByVal(SCList* phead, ElemType x)
{
	assert(phead != NULL);
	SCListNode* node = (SCListNode*)malloc(sizeof(SCListNode));
	node->data = x;
	if (SCListLength(*phead) == 0)
		SCListPushFront(phead, node);
	else
	{
		SCListNode* cur = *phead;
		SCListNode* prev = NULL;
		while (cur->data < x)
		{
			prev = cur;
			cur = cur->next;
			if (cur == *phead)
				break;
		}
		if (prev == NULL)//头插
		{
			SCListNode* last = *phead;
			while (last->next != *phead)
				last = last->next;
			node->next = *phead;
			*phead = node;
			last->next = *phead;
		}
		else
		{
			node->next = cur;
			prev->next = node;
		}
	}
}
void SCListEraseAll(SCList* phead, ElemType x)
{
	assert(phead != NULL);
	if (*phead == NULL)
	{
		printf("当前链表为空,无法进行删除操作\n");
	}
	else
	{
		SCListNode* cur = *phead;
		SCListNode* node = NULL;
		while (cur->next != *phead)
			cur = cur->next;
		cur->next = NULL;//将循环暂时断开,方便删除结点
		while (*phead != NULL && (*phead)->data == x)
		{
			node = *phead;
			*phead = node->next;
			free(node);
			node = NULL;
		}
		if (*phead == NULL)
			return;
		cur = *phead;
		SCListNode* prev = NULL,* next = cur->next;
		while (cur != NULL)
		{
			if (cur->data == x)
			{
				free(cur);
				cur = prev;
				prev->next = next;
			}
			prev = cur;
			cur = next;
			if(cur != NULL)
				next = cur->next;
		}
		prev->next = *phead;//重新连接头部
	}
}
void SCListClean(SCList* phead)
{
	SCListDestroy(phead);
}
void SCListReverse(SCList* phead)
{
	assert(phead != NULL);
	if (SCListLength(*phead) == 1 || SCListLength(*phead) == 0)
		return;
	SCListNode* p = *phead;
	SCListNode* q = p->next;

	SCListNode* last = q;
	while (last->next != *phead)
		last = last->next;
	last->next = NULL;
	p->next = *phead;//分成单向循环链表p和单链表q

	while (q != NULL)//将q中的结点一次头插入p中
	{
		p = q;
		q = q->next;

		last = *phead;
		while (last->next != *phead)
			last = last->next;
		p->next = *phead;
		*phead = p;
		last->next = *phead;
	}
}

对单向循环链表各个功能的测试模块如下:

//test.c
#define _CRT_SECURE_NO_WARNINGS

#include"commen.h"
#include"sclist.h"
int main()
{
	SCList list;
	SCListInit(&list);

	SCListNode* p = NULL;
	ElemType item;
	int select = 1;
	size_t pos;
	while (select)
	{
		printf("**************************************************\n");
		printf("***********************MENU***********************\n");
		printf("*  [1]push_back                   [2]push_front  *\n");
		printf("*  [3]show_list                   [0]quit_system *\n");
		printf("*  [4]pop_back                    [5]pop_front   *\n");
		printf("*  [6]insert_val                  [7]erase_val   *\n");
		printf("*  [8]find                        [9]length      *\n");
		printf("*  [10]earse_all                  [11]sort       *\n");
		printf("*  [12]reverse                    [13]clean      *\n");
		printf("*  [14]front                      [15]back       *\n");
		printf("**************************************************\n");
		printf("**************************************************\n");
		printf("请选择->\n");
		scanf("%d", &select);
		if (select == 0)
			break;
		switch (select)
		{
		case 0:
			select = 0;
			break;
		case 1:
			printf("请输入要插入的元素,若要退出,输入-1->\n");
			while (scanf("%d", &item), item != -1)
			{
				SCListPushBack(&list, item);
			}
			break;
		case 2:
			printf("请输入要插入的元素,若要退出,输入-1->\n");
			while (scanf("%d", &item), item != -1)
			{
				SCListPushFront(&list, item);
			}
			break;
		case 3:
			SCListShow(list);
			break;
		case 4:
			SCListPopBack(&list);
			break;
		case 5:
			SCListPopFront(&list);
			break;
		case 6:
			printf("请输入要插入的元素->\n");
			scanf("%d", &item);
			SCListSort(&list);
			SCListInsertByVal(&list, item);
			break;
		case 7:
			printf("请输入要删除的元素->\n");
			scanf("%d", &item);
			SCListEraseByVal(&list, item);
			break;
		case 8:
			printf("请输入要查找的元素->\n");
			scanf("%d", &item);
			p = SCListFind(list, item);
			if (p == NULL)
				printf("元素%d不存在\n", item);
			else
				printf("元素%d所在的位置为%d", item, p);
			break;
		case 9:
			printf("length = %d\n", SCListLength(list));
			break;
		case 10:
			printf("请输入要删除的元素->\n");
			scanf("%d", &item);
			SCListEraseAll(&list, item);
			break;
		case 11:
			SCListSort(&list);
			break;
		case 12:
			SCListReverse(&list);
			break;
		case 13:
			SCListClean(&list);
			break;
		case 14:
			if (SCListFront(&list) == -1)
				printf("该顺序表为空,无法获取其头部元素\n");
			else
				printf("头元素为%d\n", SCListFront(&list));
			break;
		case 15:
			if (SCListBack(&list) == -1)
				printf("该顺序表为空,无法获取其尾部元素\n");
			else
				printf("末尾元素为%d\n", SCListBack(&list));
			break;
		default:
			printf("输入非法,请重新选选择->\n");
			break;
		}
		system("pause");
		system("cls");
	}
	SCListDestroy(&list);
	return 0;
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值