與數組一樣,連結清單是一種線性資料結構。與數組不同,連結清單元素不存儲在連續的位置;元素使用指針連結。
為什麼使用連結清單?
數組可用于存儲類似類型的線性資料,但數組有以下限制。
1)數組的大小是固定的:是以我們必須提前知道元素數量的上限。此外,一般而言,配置設定的記憶體與使用情況無關,等于上限。
2)在元素數組中插入一個新元素是昂貴的,因為必須為新元素建立房間,并且必須移動現有元素才能建立房間。
例如,在一個系統中,如果我們在數組 id[] 中維護一個已排序的 ID 清單。
id[] = [1000, 1010, 1050, 2000, 2040]。
而如果我們要插入一個新的ID 1005,那麼為了保持排序順序,我們必須将1000之後的所有元素(不包括1000)移動。
除非使用某些特殊技術,否則删除數組的代價也很高。例如,要删除 id[] 中的 1010,必須移動 1010 之後的所有内容。
優于數組的優點
1)動态大小
2)易于插入/删除
缺點:
1)不允許随機通路。我們必須從第一個節點開始按順序通路元素。是以我們不能用它的預設實作有效地對連結清單進行二分搜尋。在這裡閱讀。
2)清單的每個元素都需要額外的指針存儲空間。
3) 對緩存不友好。由于數組元素是連續的位置,是以存在引用的局部性,而在連結清單的情況下則不存在。
表示:
連結清單由指向連結清單第一個節點的指針表示。第一個節點稱為頭部。如果連結清單為空,則頭部的值為NULL。
清單中的每個節點至少由兩部分組成:
1) 資料
2) 指向下一個節點的指針(或引用)
在 C 中,我們可以使用結構來表示一個節點。下面是一個帶有整數資料的連結清單節點的例子。
在 Java 或 C# 中,LinkedList 可以表示為一個類,而一個 Node 可以表示為一個單獨的類。LinkedList 類包含一個 Node 類類型的引用。
第一個簡單連結清單
1.C
//一個連結清單節點
struct Node {
int data;
struct Node* next;
};
2.C++
class Node {
public:
int data;
Node* next;
};
3.Java
class LinkedList {
Node head; // head of the list
/* 連結清單節點*/
class Node {
int data;
Node next;
// 建立新節點的構造函數
// next 預設初始化為 null
Node(int d) { data = d; }
}
}
4.Python
class Node:
# 初始化節點對象的函數
def __init__(self, data):
self.data = data # 配置設定資料
self.next = None # 将 next 初始化為 null
class LinkedList:
# 初始化連結清單對象的函數
def __init__(self):
self.head = None
5.C#
class LinkedList {
// 連結清單的第一個節點(head)
// 将是 Node 類型的對象(預設為 null)
Node head;
class Node {
int data;
Node next;
// 建立新節點的構造函數
Node(int d) { data = d; }
}
}
讓我們建立一個具有 3 個節點的簡單連結清單。
// 一個示例 C++ 程式來介紹
// 一個連結清單
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node* next;
};
// 程式建立一個簡單的連結
// 包含 3 個節點的清單
int main()
{
Node* head = NULL;
Node* second = NULL;
Node* third = NULL;
// 在堆中配置設定 3 個節點
head = new Node();
second = new Node();
third = new Node();
/* 三個塊已被動态配置設定。
我們有指向這三個塊的指針作為頭部,
第二個和第三個
head second third
| | |
| | |
+---+-----+ +----+----+ +----+----+
| # | # | | # | # | | # | # |
+---+-----+ +----+----+ +----+----+
# 代表任何随機值。
資料是随機的,因為我們沒有配置設定
什麼都還沒有 */
head->data = 1; // 在第一個節點配置設定資料
head->next = second; // 将第一個節點與
// 第二個節點
/* 資料已配置設定到第一個的資料部分
塊(頭部指向的塊)。 接下來
第一個塊的指針指向第二個。
是以他們兩個是有聯系的。
head second third
| | |
| | |
+---+---+ +----+----+ +-----+----+
| 1 | o----->| # | # | | # | # |
+---+---+ +----+----+ +-----+----+
*/
// 将資料配置設定給第二個節點
second->data = 2;
// 将第二個節點與第三個節點連接配接起來
second->next = third;
/* 資料已經配置設定到第二個資料部分
塊(由秒指向的塊)。 接下來
第二個塊的指針指向第三個
堵塞。 是以所有三個塊都是連結的。
head second third
| | |
| | |
+---+---+ +---+---+ +----+----+
| 1 | o----->| 2 | o-----> | # | # |
+---+---+ +---+---+ +----+----+ */
third->data = 3; // 将資料配置設定給第三個節點
third->next = NULL;
/* 資料已配置設定到第三個資料部分
塊(由第三個指向的塊)。 和下一個指針
第三塊的 NULL 表示
連結清單在這裡終止。
我們已經準備好了連結清單。
head
|
|
+---+---+ +---+---+ +----+------+
| 1 | o----->| 2 | o-----> | 3 | NULL |
+---+---+ +---+---+ +----+------+
請注意,隻有頭部足以表示
整個清單。 我們可以周遊完整的
按照下一個指針列出。*/
return 0;
}
連結清單周遊
在前面的程式中,我們建立了一個簡單的具有三個節點的連結清單。讓我們周遊建立的清單并列印每個節點的資料。對于周遊,讓我們編寫一個通用函數 printList() 來列印任何給定的清單。
// 一個用于周遊連結清單的簡單 C++ 程式
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node* next;
};
// 此函數列印連結清單的内容
// 從給定節點開始
void printList(Node* n)
{
while (n != NULL) {
cout << n->data << " ";
n = n->next;
}
}
// 驅動程式代碼
int main()
{
Node* head = NULL;
Node* second = NULL;
Node* third = NULL;
// 在堆中配置設定 3 個節點
head = new Node();
second = new Node();
third = new Node();
head->data = 1; // 在第一個節點配置設定資料
head->next = second; // 将第一個節點與第二個節點連接配接起來
second->data = 2; // 将資料配置設定給第二個節點
second->next = third;
third->data = 3; // 将資料配置設定給第三個節點
third->next = NULL;
printList(head);
return 0;
}