前言
所謂單循環鏈表,實際上就是在單鏈表的基礎上,使最後一個結點的next指針再指向頭結點,形成循環的效果。這樣,從表中任何一個結點出發都可以找到其他結點的位置。
尾指針
顧名思義,尾指針是指向鏈表的最後一個結點。在單循環鏈表中,設立尾指針能使得一些操作簡化,例如兩個單循環鏈表的合併。
注
我們之前所寫的管理結構,是既包括頭指針又包括尾指針的,因此在實現某些操作時就很方便了。
單循環鏈表和單鏈表的實現思路、注意事項都是一樣的,只是需要額外注意的是,在我們的管理結構中要注意保持last的next指針始終指向頭結點,達到循環的效果。
附:單鏈表的實現思路及注意事項
數據結構(2.1)線性表之單鏈表的表示和實現
數據結構(2.2)線性表之單鏈表的具體實現
- 鏈表爲空
- 鏈表非空
全部代碼
單循環鏈表的各項操作與單鏈表並無差別,只是在判斷鏈表結束的條件有差別,之前是判斷next指針是否爲空,現在需要判斷是否爲頭結點。因此實現代碼並沒有巨大的改變,只是在一些判斷條件上做出改變。
SCList.h
#ifndef SCList_h
#define SCList_h
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#define ElemType int
//結點的結構
typedef struct Node{
ElemType data;
struct Node *next;
}Node, *Pnode;
//鏈表的結構
typedef struct List{
Pnode first;
Pnode last;
int size;
}List;
//初始化單循環鏈表
void InitSCList(List *list);
//1.尾部插入
void push_back(List *list,ElemType x);
//2.頭部插入
void push_fount(List *list,ElemType x);
//3.展示
void show_list(List *list);
//4.尾部刪除
void pop_back(List *list);
//5.頭部刪除
void pop_fount(List *list);
//6.按值插入(要求插入前的鏈表是有序的(此處爲順序
void insert_val(List *list,ElemType x);
//7.按值查找
Node* find(List *list,ElemType x);
//8.獲取長度
int length(List *list);
//9.按值刪除
void delete_val(List *list,ElemType x);
//10.排序
void sort(List *list);
//11.逆置(前後轉換
void resver(List *list);
//12.清除單鏈表 ->只清除數據,保留頭結點
void clearList(List *list);
//13.摧毀 ->包括頭結點在內一起摧毀
void destroy(List *list);
//生成一個結點
Node* getNode(ElemType x);
#endif /* SCList_h */
SCList.cpp
#include "SCList.h"
//初始化單循環鏈表
void InitSCList(List *list){
Node *s = (Node *)malloc(sizeof(Node));
assert(s != NULL);
list->first = list->last = s;
//讓最後一個結點的next指向頭部,形成循環
list->last->next = list->first;
list->size = 0;
}
//1.尾部插入
void push_back(List *list,ElemType x){
Node *s = getNode(x);
//將這個結點接到鏈表尾部
list->last->next = s;
//重新設置last指針的指向
list->last = s;
//讓最後一個結點的next指向頭部,形成循環
list->last->next = list->first;
list->size ++;
}
//2.頭部插入
void push_fount(List *list,ElemType x){
Node *s = getNode(x);
s->next = list->first->next;
list->first->next = s;
//判斷是否是第一個結點
if (list->last == list->first) {
//是,更改last指針的指向
list->last = s;
}
list->size ++;
}
//3.展示
void show_list(List *list){
Node *p = list->first->next;
while (p != list->first) {
printf("%4d",p->data);
p = p->next;
}
printf("\n");
}
//4.尾部刪除
void pop_back(List *list){
if (list->size == 0) {
printf("無可刪除的結點!\n");
return;
}
//尋找倒數第二個結點
Node *p = list->first;
while (p->next != list->last) {
p = p->next;
}
//釋放它後一個結點(即最後一個結點)
free(list->last);
//更改last指針的指向
list->last = p;
//讓最後一個結點的next指向頭部,形成循環
list->last->next = list->first;
list->size --;
}
//5.頭部刪除
void pop_fount(List *list){
if (list->size == 0) {
printf("無可刪除的結點!\n");
return;
}
Node *p = list->first->next;
list->first->next = p->next;
free(p);
//判斷是否是最後一個結點
if(list->size == 1){
//重新設置last的指向
list->last = list->first;
}
list->size --;
}
//6.按值插入(要求插入前的鏈表是有序的(此處爲順序
void insert_val(List *list,ElemType x){
Node *p = list->first;
//尋找插入位置
while (p->next != list->last && p->next->data < x) {
p = p->next;
}
//到達了最後一個結點後,還需要與最後一個結點的值進行比較
//判斷是否比最後一個結點大
if (p->next == list->last && p->next->data < x) {
//是,直接進行尾部插入
push_back(list, x);
}else{
//其他狀況,直接在該位置進行插入
Node *s = getNode(x);
s->next = p->next;
p->next = s;
list->size ++;
}
}
//7.按值查找
Node* find(List *list,ElemType x){
if (list->size == 0) {
return NULL;
}
//遍歷整個鏈表
Node *p = list->first->next;
while (p != list->first && p->data != x) {
p = p->next;
}
//判斷是否回到頭部
if (p == list->first) {
//是,說明鏈表中沒有要找的數據
return NULL;
}else{
return p;
}
}
//8.獲取長度
int length(List *list){
return list->size;
}
//9.按值刪除
void delete_val(List *list,ElemType x){
if (list->size == 0) {
printf("鏈表爲空,無法刪除!\n");
return;
}
Node *p = find(list, x);
if (p == NULL) {
printf("要刪除的數據不存在!\n");
return;
}
//判斷是否是最後一個結點
if (p == list->last) {
//是,直接尾部刪除
pop_back(list);
}else{
//判斷是否是倒數第二個結點
if (p->next == list->last) {
//是,需要修改last指針的指向
list->last = p;
}
Node *s = p->next;
p->data = s->data;
p->next = s->next;
free(s);
list->size --;
}
}
//10.排序
void sort(List *list){
if (list->size <= 1) {
return;
}
Node *s = list->first->next;
Node *q = s->next;
//將鏈表尾部斷開
list->last->next = NULL;
//重新設置last指針
list->last = s;
//讓鏈表再次循環
list->last->next = list->first;
while (q != NULL) {
s = q;
q = q->next;
//進行按值插入
insert_val(list, s->data);
free(s);
list->size --;
// //尋找插入位置
// Node *p = list->first;
// while (p->next != list->last && p->next->data < s->data) {
// p = p->next;
// }
//
// //判斷是否是最後一個結點
// if (p->next == list->last && p->next->data < s->data) {
// //是,直接進行尾部插入
// s->next = list->last->next;
// list->last->next = s;
// list->last = s;
//
// }else{
// s->next = p->next;
// p->next = s;
// }
}
}
//11.逆置(前後轉換
void resver(List *list){
if (list->size <= 1) {
return;
}
Node *s = list->first->next;
Node *q = s->next;
list->last->next = NULL;
list->last = s;
list->last->next = list->first;
while (q != NULL) {
s = q;
q = q->next;
//進行頭部插入
push_fount(list, s->data);
free(s);
list->size--;
// //進行頭部插入
// s->next = list->first->next;
// list->first->next = s;
}
}
//12.清除單鏈表 ->只清除數據,保留頭結點
void clearList(List *list){
Node *p = list->first->next;
while (p != list->first) {
p = p->next;
pop_fount(list);
}
}
//13.摧毀 ->包括頭結點在內一起摧毀
void destroy(List *list){
clearList(list);
free(list->first);
list->first = list->last = NULL;
}
//生成一個結點
Node* getNode(ElemType x){
Node *s = (Node *)malloc(sizeof(Node));
assert(s != NULL);
s->data = x;
s->next = NULL;
return s;
}
Main.cpp
#include "SCList.h"
int main(int argc, const char * argv[]) {
List myList;
InitSCList(&myList);
//保存要輸入的數據
ElemType item;
//保存要查找的地址
Node *p = NULL;
int select = 1;
while (select) {
printf("**************************************\n");
printf("* [1] push_back [2] push_front *\n");
printf("* [3] show_list [4] pop_back *\n");
printf("* [5] pop_front [6] insert_val *\n");
printf("* [7] find [8] length *\n");
printf("* [9] delete_val [10] sort *\n");
printf("* [11] resver [12] clear *\n");
printf("* [13*] destroy [0] quit_system*\n");
printf("**************************************\n");
printf("請選擇:");
scanf("%d",&select);
if (select == 0) {
break;
}
switch (select) {
case 1:
//尾部插入
printf("請輸入要插入的數據(-1結束):");
scanf("%d",&item);
while (item != -1) {
push_back(&myList, item);
scanf("%d",&item);
}
break;
case 2:
//頭部插入
printf("請輸入要插入的數據(-1結束):");
scanf("%d",&item);
while (item != -1) {
push_fount(&myList, item);
scanf("%d",&item);
}
break;
case 3:
//展示單鏈表
show_list(&myList);
break;
case 4:
//尾部刪除
pop_back(&myList);
break;
case 5:
//頭部刪除
pop_fount(&myList);
break;
case 6:
//按值插入
printf("請輸入要插入的數據:\n");
scanf("%d",&item);
insert_val(&myList, item);
break;
case 7:
//按值查找
printf("請輸入要查找的值:\n");
scanf("%d",&item);
p = find(&myList, item);
if (p == NULL) {
printf("要查找的數據不存在!\n");
}else{
printf("地址爲:%p\n",p);
}
break;
case 8:
//展示鏈表長度
printf("鏈表的長度爲:%d\n",length(&myList));
break;
case 9:
//按值刪除
printf("請輸入要刪除的值:\n");
scanf("%d",&item);
delete_val(&myList, item);
break;
case 10:
//排序
sort(&myList);
break;
case 11:
//逆置(前後轉換
resver(&myList);
break;
case 12:
//清除
clearList(&myList);
break;
case 13:
destroy(&myList);
break;
default:
printf("輸入的命令有誤,請重新插入\n");
break;
}
}
return 0;
}