連結串列是一種隨機儲存在記憶體中的叫做節點的物件集合。
節點包含兩個欄位,即儲存在該地址的資料和包含下一個節點地址的指標。
連結串列的最後一個節點包含指向null
的指標。
到目前為止,學習了如何使用陣列資料結構來組織要在記憶體中單獨儲存的元素組。 但是,陣列有幾個優點和缺點,必須知道這些優點和缺點才能確定將在整個程式中使用的什麼樣型別的資料結構。
陣列有以下限制:
連結串列是可以克服陣列所有限制的資料結構。 連結串列是非常有用的,因為,
單連結串列是有序元素集的集合。元素的數量可以根據程式的需要而變化。 單連結串列中的節點由兩部分組成:資料部分和連結部分。 節點的資料部分儲存將由節點表示的實際資訊,而節點的連結部分儲存其直接後繼的地址。
單向鏈或單連結串列可以僅在一個方向上遍歷。也就是說每個節點只包含下一個節點的指標,因此不能反向遍歷連結串列。
考慮一個例子,學生在三個科目的成績儲存在如圖所示的連結串列中 -
在上圖中,箭頭表示連結。每個節點的資料部分包含學生在不同科目成績。連結串列中的最後一個節點由空指標標識,該空指標存在於最後一個節點的地址部分中。可在連結串列的資料部分中包含所需的資料元素。
複雜度
時間複雜度 -
操作 | 平均複雜度 | 最壞複雜度 |
---|---|---|
存取 | θ(n) | θ(n) |
搜尋 | θ(n) | θ(n) |
插入 | θ(1) | θ(1) |
刪除 | θ(1) | θ(1) |
可以在單連結串列上執行各種操作。下面給出了所有這些操作列表。
struct node
{
int data;
struct node *next;
};
struct node *head, *ptr;
ptr = (struct node *)malloc(sizeof(struct node *));
在不同位置執行插入節點到單個連結串列。根據插入的新節點的位置,插入分為以下類別。
編號 | 操作 | 描述 |
---|---|---|
1 | 插入到連結串列開頭 | 它涉及在連結串列的前面插入任何元素。只需要進行一些連結調整,以使新節點成為連結串列的頭部。 |
2 | 插入到連結串列末尾 | 它涉及插入連結串列的最後一個位置。 新節點可以作為列表中的唯一節點插入,也可以作為最後一個插入。在每個場景中實現不同的邏輯。 |
3 | 在指定節點之後插入 | 它涉及在連結串列的指定節點之後插入。需要跳過所需數量的節點才能到達指定節點,之後插入新節點。 |
在不同位置執行從單連結串列中刪除節點。根據要刪除的節點的位置,操作分為以下類別。
編號 | 操作 | 描述 |
---|---|---|
1 | 刪除連結串列開頭節點 | 它涉及從連結串列的開頭節點刪除。這是所有操作中最簡單的操作。它只需要在節點指標中進行一些調整。 |
2 | 刪除連結串列末尾節點 | 它涉及刪除列表的最後一個節點。連結串列可以為空或完整。針對不同場景實現不同的邏輯。 |
3 | 刪除指定節點之後節點 | 它涉及刪除連結串列中指定節點之後的節點。需要跳過所需數量的節點才能到達節點,之後的節點將被刪除。這需要遍歷連結串列。 |
4 | 遍歷 | 在遍歷中,簡單地存取連結串列的每個節點至少一次,以便對其執行某些特定操作,例如,列印列表中存在的每個節點的資料部分。 |
5 | 搜尋 | 在搜尋中,將連結串列的每個元素與給定元素匹配。 如果在任何位置找到該元素,則返回該元素的位置,否則返回null 。。 |
選單驅動程式,用於實現單連結串列上的所有操作(使用C語言實現),程式碼如下所示 -
#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *head;
void beginsert();
void lastinsert();
void randominsert();
void begin_delete();
void last_delete();
void random_delete();
void display();
void search();
void main()
{
int choice = 0;
while (choice != 9)
{
printf("\n\n********* 主選單 *********\n");
printf("從以下選單列表中選擇一個選項操作 ...\n");
printf("===============================================\n");
printf("1.插入到開頭\n");
printf("2.插入到結尾\n");
printf("3.插入任何隨機位置\n");
printf("4.從頭部刪除\n");
printf("5.從尾部刪除\n");
printf("6.刪除指定位置後的節點\n");
printf("7.搜尋元素\n");
printf("8.顯示連結串列中的資料\n");
printf("9.退出\n\n");
printf("===============================================\n");
printf("請輸入您的選擇:");
scanf("%d", &choice);
switch (choice)
{
case 1:
beginsert();
break;
case 2:
lastinsert();
break;
case 3:
randominsert();
break;
case 4:
begin_delete();
break;
case 5:
last_delete();
break;
case 6:
random_delete();
break;
case 7:
search();
break;
case 8:
display();
break;
case 9:
exit(0);
break;
default:
printf("請輸入有效的選項...");
}
}
}
void beginsert()
{
struct node *ptr;
int item;
ptr = (struct node *) malloc(sizeof(struct node *));
if (ptr == NULL)
{
printf("記憶體不夠!\n");
}
else
{
printf("請輸入一個整數值:");
scanf("%d", &item);
ptr->data = item;
ptr->next = head;
head = ptr;
printf("節點已經成功插入\n");
}
}
void lastinsert()
{
struct node *ptr, *temp;
int item;
ptr = (struct node*)malloc(sizeof(struct node));
if (ptr == NULL)
{
printf("記憶體不夠!\n");
}
else
{
printf("請輸入一個整數值:");
scanf("%d", &item);
ptr->data = item;
if (head == NULL)
{
ptr->next = NULL;
head = ptr;
printf("節點已經成功插入\n");
}
else
{
temp = head;
while (temp->next != NULL)
{
temp = temp->next;
}
temp->next = ptr;
ptr->next = NULL;
printf("節點已經成功插入\n");
}
}
}
void randominsert()
{
int i, loc, item;
struct node *ptr, *temp;
ptr = (struct node *) malloc(sizeof(struct node));
if (ptr == NULL)
{
printf("記憶體不夠!\n");
}
else
{
printf("請輸入一個整數值:");
scanf("%d", &item);
ptr->data = item;
printf("輸入要插入的位置:");
scanf("%d", &loc);
temp = head;
for (i = 0;i < loc;i++)
{
temp = temp->next;
if (temp == NULL)
{
printf("此處不能插入節點\n");
return;
}
}
ptr->next = temp->next;
temp->next = ptr;
printf("節點已經成功插入\n");
}
}
void begin_delete()
{
struct node *ptr;
if (head == NULL)
{
printf("連結串列為空,沒有什麼可以刪除!\n");
}
else
{
ptr = head;
head = ptr->next;
free(ptr);
printf("已經刪除頭部節點 ...\n");
}
}
void last_delete()
{
struct node *ptr, *ptr1;
if (head == NULL)
{
printf("連結串列為空,沒有什麼可以刪除!\n");
}
else if (head->next == NULL)
{
head = NULL;
free(head);
printf("唯一的節點已經被刪除了...\n");
}
else
{
ptr = head;
while (ptr->next != NULL)
{
ptr1 = ptr;
ptr = ptr->next;
}
ptr1->next = NULL;
free(ptr);
printf("已刪除最後一個節點...\n");
}
}
void random_delete()
{
struct node *ptr, *ptr1;
int loc, i;
printf("輸入要在此節點之後執行刪除的節點的位置:");
scanf("%d", &loc);
ptr = head;
for (i = 0;i < loc;i++)
{
ptr1 = ptr;
ptr = ptr->next;
if (ptr == NULL)
{
printf("不能刪除\n");
return;
}
}
ptr1->next = ptr->next;
free(ptr);
printf("\n第 %d 個節點已經被刪除了", loc + 1);
}
void search()
{
struct node *ptr;
int item, i = 0, flag;
ptr = head;
if (ptr == NULL)
{
printf("連結串列為空!\n");
}
else
{
printf("請輸入要搜尋的專案:");
scanf("%d", &item);
while (ptr != NULL)
{
if (ptr->data == item)
{
printf("在 %d 位置找到資料項\n", i + 1);
flag = 0;
}
else
{
flag = 1;
}
i++;
ptr = ptr->next;
}
if (flag == 1)
{
printf("資料項未找到\n");
}
}
}
/**
* 顯示連結串列中的資料
*/
void display()
{
struct node *ptr;
ptr = head;
if (ptr == NULL)
{
printf("連結串列為空,沒有資料可以顯示。");
}
else
{
printf("連結串列中的資料值如下所示:\n");
printf("--------------------------------------------------\n");
while (ptr != NULL)
{
printf("\n%d", ptr->data);
ptr = ptr->next;
}
}
printf("\n\n\n");
}
輸出結果如下 -
********* 主選單 *********
從以下選單列表中選擇一個選項操作 ...
===============================================
1.插入到開頭
2.插入到結尾
3.插入任何隨機位置
4.從頭部刪除
5.從尾部刪除
6.刪除指定位置後的節點
7.搜尋元素
8.顯示連結串列中的資料
9.退出
===============================================
請輸入您的選擇:1
請輸入一個整數值:111
節點已經成功插入
********* 主選單 *********
從以下選單列表中選擇一個選項操作 ...
===============================================
1.插入到開頭
2.插入到結尾
3.插入任何隨機位置
4.從頭部刪除
5.從尾部刪除
6.刪除指定位置後的節點
7.搜尋元素
8.顯示連結串列中的資料
9.退出
===============================================
請輸入您的選擇:2
請輸入一個整數值:2222
節點已經成功插入
********* 主選單 *********
從以下選單列表中選擇一個選項操作 ...
===============================================
1.插入到開頭
2.插入到結尾
3.插入任何隨機位置
4.從頭部刪除
5.從尾部刪除
6.刪除指定位置後的節點
7.搜尋元素
8.顯示連結串列中的資料
9.退出
......