必威电竞|足球世界杯竞猜平台

循環(huán)鏈表
來源:互聯(lián)網(wǎng)

循環(huán)鏈表是一種特殊的鏈式存儲結構,其中最后一個節(jié)點的指針域指向頭部節(jié)點,從而形成了一個閉環(huán)。這種結構使得從任意節(jié)點出發(fā)都能夠訪問到列表中的所有節(jié)點。循環(huán)鏈表的操作通常比單鏈表更便捷,因為它們不需要額外的存儲空間,只需要稍微調整鏈表的鏈接方式。

數(shù)據(jù)結構

存儲結構

```c

typedef struct LNode {

ElemType 數(shù)據(jù);

struct LNode *next;

} LNode, *LinkList;

```

基本操作

構造空表

```c

void InitList(LinkList *L)

{

// 操作結果:構造一個空的線性表L

*L = (LinkList)malloc(sizeof(struct LNode));

if (!*L) // 存儲分配失敗

exit(OVERFLOW);

(*L)->next = *L; // 指針域指向頭結點

}

```

銷毀表

```c

void DestroyList(LinkList *L)

{

// 操作結果:銷毀線性表L

LinkList q, p = (*L)->next; // p指向頭結點

while (p != *L) // 沒到表尾

{

q = p->樂華七子NEXT;

free(p);

p = q;

}

free(*L);

*L = NULL;

}

```

清除表

```c

void ClearList(LinkList *L)

{

// 初始條件:線性表L已存在。操作結果:將L重置為空表

LinkList p, q;

*L = (*L)->next; // L指向頭結點

p = (*L)->next; // p指向第一個結點

while (p != *L) // 沒到表尾

{

q = p->樂華七子NEXT;

free(p);

p = q;

}

(*L)->next = *L; // 頭結點指針域指向自身

}

```

判斷表是否為空

```c

Status ListEmpty(LinkList L)

{

// 初始條件:線性表L已存在。操作結果:若L為空表,則返回TRUE,否則返回FALSE

if (L->next == L) // 空

return TRUE;

else

return FALSE;

}

```

計算表長度

```c

int ListLength(LinkList L)

{

// 初始條件:L已存在。操作結果:返回L中數(shù)據(jù)元素個數(shù)

int i = 0;

LinkList p = L->next; // p指向頭結點

while (p != L) // 沒到表尾

{

i++;

p = p->next;

}

return i;

}

```

獲取元素

```c

Status GetElem(LinkList L, int i, ElemType *e)

{

// 當?shù)趇個元素存在時,其值賦給e并返回OK,否則返回ERROR

int j = 1; // 初始化,j為計數(shù)器

LinkList p = L->next->next; // p指向第一個結點

if (i <= 0 || i > ListLength(L)) // 第i個元素不存在

return ERROR;

while (j < i)

{

/* 順指針向后查找,直到p指向第i個元素 */

p = p->next;

j++;

}

*e = p->數(shù)據(jù); // 取第i個元素

return OK;

}

```

查找元素

```c

int LocateElem(LinkList L, ElemType e, Status(*compare)(ElemType, ElemType))

{

// 初始條件:線性表L已存在,compare()是數(shù)據(jù)元素判定函數(shù)

// 操作結果:返回L中第1個與e滿足關系compare()的數(shù)據(jù)元素的位序。

// 若這樣的數(shù)據(jù)元素不存在,則返回值為0

int i = 0;

LinkList p = L->next->next; // p指向第一個結點

while (p != L->next)

{

i++;

if (compare(p->數(shù)據(jù), e)) // 滿足關系

return i;

p = p->next;

}

return 0;

}

```

獲取前驅元素

```c

Status PriorElem(LinkList L, ElemType cur_e, ElemType *pre_e)

{

// 初始條件:線性表L已存在

// 操作結果:若cur_e是L的數(shù)據(jù)元素,且不是第一個,則用pre_e返回它的前驅,

// 否則操作失敗,pre_e無定義

LinkList q, p = L->next->next; // p指向第一個結點

q = p->樂華七子NEXT;

while (q != L->next) // p沒到表尾

{

if (q->數(shù)據(jù) == cur_e)

{

*pre_e = p->data;

return TRUE;

}

p = q;

q = q->next;

}

return FALSE; // 操作失敗

}

```

獲取后繼元素

```c

Status NextElem(LinkList L, ElemType cur_e, ElemType *next_e)

{

// 初始條件:線性表L已存在

// 操作結果:若cur_e是L的數(shù)據(jù)元素,且不是最后一個,則用next_e返回它的后繼,

// 否則操作失敗,next_e無定義

LinkList p = L->next->next; // p指向第一個結點

while (p != L) // p沒到表尾

{

if (p->數(shù)據(jù) == cur_e)

{

*next_e = p->樂華七子NEXT>data;

return TRUE;

}

p = p->next;

}

return FALSE; // 操作失敗

}

```

插入元素

```c

Status ListInsert(LinkList *L, int i, ElemType e)

{

// 改變L

// 在L的第i個位置之前插入元素e

LinkList p = (*L)->next, s; // p指向頭結點

int j = 0;

if (i <= 0 || i > ListLength(*L) + 1) // 無法在第i個元素之前插入

return ERROR;

while (j < i - 1)

{

p = p->next;

j++;

}

s = (LinkList)malloc(sizeof(struct LNode)); // 生成新結點

s->數(shù)據(jù) = e; // 插入L中

s->next = p->next;

p->next = s;

if (p == *L) // 改變尾結點

*L = s;

return OK;

}

```

刪除元素

```c

Status ListDelete(LinkList *L, int i, ElemType *e)

{

// 改變L

// 刪除L的第i個元素,并由e返回其值

LinkList p = (*L)->next, q; // p指向頭結點

int j = 0;

if (i <= 0 || i > ListLength(*L)) // 第i個元素不存在

return ERROR;

while (j < i - 1)

{

p = p->next;

j++;

}

q = p->next; // q指向待刪除結點

p->next = q->next;

*e = q->數(shù)據(jù);

if (*L == q) // 刪除的是表尾元素

*L = p;

free(q); // 釋放待刪除結點

return OK;

}

```

遍歷表

```c

void ListTraverse(LinkList L, void(*vi)(ElemType))

{

// 初始條件:L已存在。操作結果:依次對L的每個數(shù)據(jù)元素調用函數(shù)vi()

LinkList p = L->next->next; // p指向首元結點

while (p != L->next) // p不指向頭結點

{

vi(p->數(shù)據(jù));

p = p->next;

}

printf("\n");

}

```

應用問題

Josephu問題:據(jù)傳,猶太歷史學家Josephus曾講述過這樣一個故事:在羅馬人占領喬塔帕特后,39名猶太人與Josephus及其朋友躲進了一個山洞,他們決定以一種自殺的方式結束生命,即41個人圍成一圈,從第一個人開始報數(shù),每報到第三個人就要自殺,以此類推,直到所有人都死去。然而,Josephus和他的朋友并不愿意這樣做,他們計劃通過巧妙地安排自己的位置來幸免于難。Josephus將自己和朋友分別安排在第16個和第31個位置,最終成功逃脫了這場死亡游戲。

如何使用循環(huán)鏈表解決Josephu問題呢?

類型分類

循環(huán)鏈表可以分為兩類:單循環(huán)鏈表和多重鏈的循環(huán)鏈表。前者是在單鏈表的基礎上,將終端結點的指針域設置為指向表頭結點;后者則是將表中結點鏈接在多個環(huán)上。

特點

循環(huán)鏈表具有以下特點:

- 不需要額外的存儲空間,僅通過對鏈表鏈接方式進行微小改動,就能使其處理變得更加便捷靈活。

- 在循環(huán)鏈表上實現(xiàn)某些特定的運算會更為容易,比如在單循環(huán)鏈表上實現(xiàn)將兩個線性表連接成一個新的線性表的運算,其執(zhí)行時間僅為常數(shù)級別,而如果在單鏈表或頭指針表示的單循環(huán)表上進行同樣的操作,則需要遍歷整個鏈表,執(zhí)行時間會隨鏈表長度呈線性增長。

實際應用

循環(huán)鏈表的實際應用非常廣泛,特別是在計算機科學領域。例如,在操作系統(tǒng)中,進程調度隊列就可以使用循環(huán)鏈表來實現(xiàn),這樣能夠快速地定位隊列中的任意進程,并對其進行調度。此外,循環(huán)鏈表還被用于實現(xiàn)各種數(shù)據(jù)結構,如哈希表、堆棧和隊列等。

參考資料 >

循環(huán)鏈表與雙鏈表 .CSDN博客 .2024-08-29

鏈表.知乎.2024-08-29

《循環(huán)鏈表》 .CSDN博客 .2024-08-29

生活家百科家居網(wǎng)