不带头单向循环链表结构如下:
其中,详细介绍不带头单向循环链表的排序功能的实现。
以以下链表为例:
第一步:
将该单向循环链表分成只有一个结点的单向循环链表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;
}