鍊式存儲結構
- 結點在存儲器中的位置是任意的,即邏輯上相鄰的資料元素在實體上不一定相鄰
有關術語
- 結點:資料元素的存儲映像。由資料域和指針域兩部分組成
- 資料域:存儲元素數值資料
- 指針域:存儲直接後繼結點的存儲位置
- 連結清單:n 個結點由指針鍊組成一個連結清單。它是線性表的鍊式存儲映像,稱為線性表的鍊式存儲結構
- 單連結清單
- 結點隻有一個指針域的連結清單,稱為單連結清單或線性連結清單
- 雙連結清單
- 有兩個指針域的連結清單,稱為雙連結清單
- 循環連結清單
- 首尾相接的連結清單稱為循環連結清單
- 單連結清單
- 頭指針
- 指向連結清單中第一個結點的指針
- 首元結點
- 指連結清單中存儲第一個資料元素a1的結點
- 頭結點
- 在連結清單的首元結點之前附設的一個結點;資料域内隻放空表标志和表長等資訊
- 設定頭結點的好處
- 便于首元結點的處理
- 首元結點的位址儲存在頭結點的指針域中,是以在連結清單的第一個位置上的操作和其它位置一緻,無須進行特殊處理;
- 便于空表和非空表的統一處理
- 無論連結清單是否為空,頭指針都是指向頭結點的非空指針,是以空表和非空表的處理也就統一了。
- 便于首元結點的處理
連結清單的特點
- 通路時隻能通過頭指針進傳入連結表,并通過每個結點的指針域向後掃描其餘結點,是以尋找第一個結點和最後一個結點所花費的時間不等
連結清單的優缺點
- 優點
- 資料元素的個數可以自由擴充
- 插入、删除等操作不必移動資料,隻需修改連結指針,修改效率較高
- 缺點
- 存儲密度小
- 存取效率不高,必須采用順序存取,即存取資料元素時,隻能按連結清單的順序進行通路(順藤摸瓜)
順序表和連結清單的比較
存儲結構比較項目 | 順序表 | 連結清單 |
---|---|---|
存儲空間 | 預先配置設定,會導緻空間閑置或溢出現象 | 動态配置設定,不會出現存儲空間閑置或溢出現象 |
存儲密度 | 不用為表示結點間的邏輯關系而增加額外的存儲開銷,存儲密度等于1 | 需要借助指針來展現元素間的邏輯關系,存儲密度小于1 |
存取元素 | 随機存取,按位置通路元素的時間複雜度為O(1) | 順序存取,按位置通路元素時間複雜度為O(n) |
插入、删除 | 平均移動約表中一半元素,時間複雜度為O(n) | 不需移動元素,确定插入、删除位置後,時間複雜度為O(1) |
适用情況 | ① 表長變化不大,且能事先确定變化的範圍 ② 很少進行插入或删除操作,經常按元素位置序号通路資料元素 | ① 長度變化較大 ② 頻繁進行插入或删除操作 |
C++代碼實作
#include<iostream>
#include<stdlib.h>
using namespace std;
#define OVERFLOW -2
#define OK 1
#define ERROR -1
typedef int Status;
typedef int Elemtype;
/* typedef struct LNode{
Elemtype data;
struct LNode *next;
}LNode;
typedef struct{
lnode *l;
}LinkList; */
typedef struct LNode {
Elemtype data;
struct LNode* next;
}LNode, * LinkList;
// 構造一個空的單連結清單
Status InitList(LinkList& L)
{
L = new LNode; // 頭指針L指向頭結點
if (!L) exit(OVERFLOW);
L->next = NULL; // 指針域置空
return OK;
}
// 前插法建立單連結清單
void CreateList_H(LinkList& L, int n)
{
LinkList p;
int i;
L = new LNode;
L->next = NULL; // 先建立一個帶頭結點的空連結清單
// for(i = 0; i < n; ++i)
for (i = 1; i < n + 1; ++i)
{
cout << "請輸入第" << i << "個結點的資料" << endl;
p = new LNode; // 生成新結點*p
cin >> p->data; // 輸入元素指派給新結點*p的資料域
p->next = L->next;
L->next = p; // 将新結點*p插入到頭結點之後
}
}
// 尾插法建立單連結清單
Status CreateList_L(LinkList& L, int n)
{
LinkList r, p;
int i;
L = new LNode;
L->next = NULL;
// 尾結點指向頭結點
r = L;
for (i = 1; i < n + 1; ++i)
{
cout << "請輸入第" << i << "個結點的資料" << endl;
p = new LNode; // 生成新結點
cin >> p->data;
p->next = NULL;
r->next = p;
r = p;
}
return OK;
}
// 取值
Status GetElem(LinkList L, int i, Elemtype& e)
{
// 根據序号i擷取元素的值,用e傳回值
int j;
LinkList p;
for (p = L->next, j = 1; j < i && p; j++)
p = p->next;
if (!p || j > i) return ERROR;
e = p->data;
return OK;
}
// 在連結清單中查找值為e的元素的位置,傳回其位址
LinkList LocateElem_L(LinkList L, Elemtype e)
{
LinkList p;
p = L->next;
while (p && p->data != e)
{
p = p->next;
}
return p;
}
// 插入
Status ListInsert(LinkList& L, int i, Elemtype& e)
{
LinkList p, s;
int j;
for (p = L, j = 0;j < i - 1 && p; j++)
p = p->next;
if (!p || j > i) return ERROR;
s = new LNode;
s->data = e;
s->next = p->next;
p->next = s;
return OK;
}
// 删除
Status ListDelete(LinkList& L, int i, Elemtype& e)
{
LinkList p, q;
int j;
for (p = L, j = 0;j < i - 1 && p; j++)
p = p->next;
if (!p || j > i) return ERROR;
q = p->next;
p->next = q->next;
e = q->data;
delete q;
return OK;
}
// 銷毀
Status DestroyList(LinkList& L)
{
LinkList p;
while (L)
{
p = L;
L = L->next;
delete p;
}
return OK;
}
// 清空
Status ClearList(LinkList& L)
{
LinkList p, q;
p = L->next; // p指向第一個結點
while (p) // 沒到表尾
{
q = p->next;
delete p;
p = q;
}
L->next = NULL; // 頭結點指針域為空
return OK;
}
// 求表長
int ListLength_L(LinkList L){
// 傳回L中資料元素的個數
int i;
LinkList p;
p = L->next; // p指向第一個結點
i = 0;
while (p) // 周遊單連結清單,統計結點數
{
i++;
p = p->next;
}
return i;
}
// 判斷表是否為空
int ListEmpty(LinkList L) {
// 若L為空,傳回1;否則,傳回0
if (L->next)
return 0;
else
return 1;
}
int main()
{
LinkList L;
Elemtype e;
int i, n;
// 建立連結清單測試
cout << "請輸入表長:";
cin >> n;
// 尾插法建立
CreateList_L(L, n);
cout << "表長為:";
cout << ListLength_L(L) << endl;
// 查找測試
cout << "請輸入您需要查找元素的位置:";
cin >> i;
GetElem(L, i, e);
cout << e;
// 删除測試
cout << "請輸入您要删除的元素的位置:";
cin >> i;
ListDelete(L, i, e);
cout << e;
return 0;
}
Python代碼實作
-
SingleNode
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019-10-02 09:32:38 # @Author : Your Name ([email protected]) # @Link : http://example.org # @Version : $Id$ class SingleNode(object): def __init__(self, item): self.item = item self.next = None class SingleLinkList(object): def __init__(self): self._head = None def isEmpty(self): return self._head == None def length(self): cur = self._head count = 0 while cur: count += 1 cur = cur.next return count def travel(self): cur = self._head while cur: print(cur.item, end=" ") cur = cur.next print() return None def addFirst(self, item): node = SingleNode(item) node.next = self._head self._head = node def append(self, item): node = SingleNode(item) if self.isEmpty(): self._head = node else: cur = self._head while cur.next: cur = cur.next cur.next = node def insert(self, pos, item): if pos <= 0: self.addFirst(item) elif pos > (self.length() - 1): self.append(item) else: node = SingleNode(item) count = 0 pre = self._head # 資料從0開始 # 從1開始 應該為 pos - 2 while count < (pos - 1): count += 1 pre = pre.next node.next = pre.next pre.next = node def remove(self, item): cur = self._head pre = None while cur: if cur.item == item: if not pre: self._head = cur.next else: pre.next = cur.next break else: pre = cur cur = cur.next def search(self, item): cur = self._head while cur: if cur.item == item: return True cur = cur.next return False if __name__ == '__main__': sll = SingleLinkList() sll.addFirst(10) sll.addFirst(20) sll.append(30) sll.travel() sll.remove(10) sll.travel() print(sll.search(30)) print(sll.search(10)) sll.insert(2, 40) sll.travel() print(sll.length()) print(sll.isEmpty()) sll.insert(2, 50) sll.travel()
20 10 30 20 30 True False 20 30 40 3 False 20 30 50 40 [Finished in 0.6s]
-
SingleCycLinkedList
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019-10-02 11:13:14 # @Author : Your Name ([email protected]) # @Link : http://example.org # @Version : $Id$ class SingleNode(object): def __init__(self, item): self.item = item self._head = None class SingleCysLinkedList(object): def __init__(self): self._head = None def is_empty(self): return self._head == None def length(self): if self.is_empty(): return 0 count = 1 cur = self._head while cur.next != self._head: count += 1 cur = cur.next return count def travel(self): if self.is_empty(): return cur = self._head print(cur.item, end=" ") while cur.next != self._head: cur = cur.next print(cur.item, end=" ") print() def addFirst(self, item): node = SingleNode(item) if self.is_empty(): self._head = node node.next = self._head else: node.next = self._head cur = self._head while cur.next != self._head: cur = cur.next cur.next = node self._head = node def append(self, item): node = SingleNode(item) if self.is_empty(): self._head = node node.next = self._head else: node.next = self._head cur = self._head while cur.next != self._head: cur = cur.next cur.next = node node.next = self._head def insert(self, pos, item): if pos<= 0: self.addFirst(item) elif pos > (self.length() - 1): self.append(item) else: node = SingleNode(item) cur = self._head count = 0 while count < (pos - 1): count += 1 cur = cur.next node.next = cur.next cur.next = node def remove(self, item): if self.is_empty(): return cur = self._head pre = None if cur.item == item: # 删除第一個元素 if cur.next != self._head: while cur.next != self._head: cur = cur.next cur.next = self._head.next self._head = self._head.next else: # 隻有一個元素 self._head = None else: pre = self._head while cur.next != self._head: if cur.item == item: pre.next = cur.next return else: pre = cur cur = cur.next if cur.item == item: pre.next = cur.next def search(self, item): if self.is_empty(): return False cur = self._head if cur.item == item: return True while cur.next != self._head: cur = cur.next if cur.item == item: return True return False if __name__ == '__main__': ll = SingleCysLinkedList() ll.addFirst(1) ll.addFirst(2) ll.append(3) ll.insert(2, 4) ll.insert(4, 5) ll.insert(0, 6) print("length: {0}".format(ll.length())) ll.travel() print(ll.search(3)) print(ll.search(7)) ll.remove(1) print("length:", ll.length()) ll.travel()
length: 6 6 2 1 4 3 5 True False length: 5 6 2 4 3 5 [Finished in 0.4s]
-
DLinkList
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019-10-02 12:10:18 # @Author : Your Name ([email protected]) # @Link : http://example.org # @Version : $Id$ class Node(object): def __init__(self, item): self.item = item self.next = None self.prev = None class DLinkList(object): def __init__(self): self._head = None def is_empty(self): return self._head == None def length(self): cur = self._head count = 0 while cur: count += 1 cur = cur.next return count def travel(self): cur = self._head while cur: print(cur.item, end=" ") cur = cur.next print() def add(self, item): node = Node(item) if self.is_empty(): self._head = node else: node.next = self._head self._head.prev = node self._head = node def append(self, item): node = Node(item) if self.is_empty(): self._head = node else: cur = self._head while cur.next: cur = cur.next cur.next = node node.prev = cur def search(self, item): cur = self._head while cur: if cur.item == item: return True cur = cur.next return False def insert(self, pos, item): if pos <= 0: self.add(item) elif pos > (self.length() - 1): self.append(item) else: node = Node(item) cur = self._head count = 0 # 移動到指定位置的前一個位置 while count < (pos - 1): count += 1 cur = cur.next # 将node的prev指向cur node.prev = cur # 将node的next指向cur的下一個結點 node.next = cur.next # 将cur的下一個結點的prev指向node cur.next.prev = node # 将cur的next指向node cur.next = node def remove(self, item): if self.is_empty(): return else: cur = self._head if cur.item == item: if cur.next == None: self._head = None else: cur.next.prev = None self._head = cur.next return while cur: if cur.item == itme: cur.prev.next = cur.next cur.next.prev = cur.prev break cur = cur.next if __name__ == '__main__': ll = DLinkList() ll.add(1) ll.add(2) ll.append(3) ll.insert(2, 4) ll.insert(4, 5) ll.insert(0, 6) print("length:", ll.length()) ll.travel() print(ll.search(3)) print(ll.search(4)) ll.remove(1) print("length: {}".format(ll.length())) ll.travel()
length: 6 6 2 1 4 3 5 True True length: 5 2 1 4 3 5 [Finished in 0.1s]