線性結構 陣列與連結串列
線性結構
線性資料結構有兩端,有時被稱為左右,某些情況被稱為前後。你也可以稱為頂部和底部,名字都不重要。將兩個線性資料結構區分開的方法是新增和移除項的方式,特別是新增和移除項的位置。例如一些結構允許從一端新增項,另一些允許從另一端移除項。
陣列或列表
陣列(Array)是程式設計界最常見的資料結構,有些程式語言被稱作位列表(List)。幾乎所有程式語言都原生內建陣列型別,只是形式向略有不同,因為陣列是最簡單的記憶體資料結構。
陣列的定義是:一個儲存元素的線性集合(Collection),元素可以通過索引(Index)來任意存取,索引通常是數字,用來計算元素之間儲存位置的偏移量。
連結串列
陣列的缺點:要儲存多個元素,陣列(或列表)可能是最常見的資料結構。但是陣列不總是組織資料的最佳結構。在大多數程式語言中,陣列的大小是固定的,所以當陣列被填滿時,再要加入新的元素會非常困難。並且從陣列起點或中間插入或移除元素的成本很高,因為需要將陣列中的其他元素向前後平移。
連結串列(Linked list)中的元素在記憶體中不是連續存放的。連結串列是由一組節點(Node)組成的集合,每個節點由元素本身和一個指向下一個元素的引用(也被稱作連結或指標)組成。相對於陣列,連結串列的好處在於,新增或移除元素的時候不需要移動其他元素。
連結串列的種類
單向連結串列(Singly linked list):是最基本的連結串列,每個節點一個引用,指向下一個節點。單向連結串列的第一個節點稱為頭節點(head node),最後一個節點稱為尾節點(tail node),尾節點的引用為空(None),不指向下一個節點。
雙向連結串列(Doubly linked list)和單向連結串列的區別在於,在連結串列中的節點引用是雙向的,一個指向下一個元素,一個指向上一個元素。
迴圈連結串列(Circular linked list)和單向連結串列類似,節點型別都一樣。唯一的區別是 ,連結串列的尾節點引用指向頭節點。
雙向迴圈連結串列:類似於雙向連結串列,尾節點的後置引用指向頭節點,頭節點的前置引用指向尾節點。
單向連結串列的操作
方法 | 操作 |
---|---|
append | 向連結串列尾部新增一個元素 |
insert | 在連結串列的指定位置插入一個元素 |
pop | 從連結串列特定位置刪除並返回元素 |
remove | 從連結串列中刪除給定的元素 |
find | 返回元素的索引 |
iter | 迭代連結串列元素 |
size | 獲取連結串列大小 |
clear | 清空連結串列 |
Python實現單向連結串列
# python3
class Node:
def __init__(self, value=None, next=None):
self.value = value
self.next = next
class LinkedList:
def __init__(self):
self.head = None
self.tail = None
self.size = 0
def append(self, value):
node = Node(value)
if self.head is None:
self.head = node
self.tail = node
else:
self.tail.next = node
self.tail = node
self.size += 1
def insert(self, index, value):
if 0 <= index <= self.size:
node = Node(value)
current = self.head
previous = Node(next=current)
count = 0
while count < index:
previous = current
current = current.next
count += 1
previous.next = node
node.next = current
if previous.value is None:
self.head = node
if node.next is None:
self.tail = node
self.size += 1
return True
else:
return False
def pop(self, index):
if 0 <= index <= self.size and self.head is not None:
current = self.head
previous = Node(next=current)
count = 0
while count < index:
previous = current
current = current.next
count += 1
previous.next = current.next
if previous.value is None:
self.head = current.next
if current.next is None:
self.tail = previous
self.size -= 1
return current.value
else:
return None
def remove(self, item):
found = False
current = self.head
previous = Node(next=current)
index = 0
while not found and current is not None:
if current.value == item:
found = True
else:
previous = current
current = current.next
index += 1
if found:
previous.next = current.next
if previous.value is None:
self.head = current.next
if current.next is None:
self.tail = previous
self.size -= 1
return index
else:
return -1
def find(self, item):
current = self.head
count = 0
while current is not None:
if current.value == item:
return count
else:
current = current.next
count += 1
return -1
def iter(self):
current = self.head
while current is not None:
yield current.value
current = current.next
def size(self):
return self.size
def clear(self):
self.head = None
self.tail = None
self.size = 0
def is_empty(self):
return self.size == 0
def __len__(self):
return self.size()
def __iter__(self):
iter self.iter()
def __getitem__(self, index):
return self.find(index)
def __contains__(self, item):
return self.find(item) != -1
JavaScript實現單向連結串列
// ES6
class Node {
constructor(value=null, next=null) {
this.value = value;
this.next = next;
}
}
class LinkedList {
constructor() {
this.head = null;
this.tail = null;
this.size = 0;
}
append(value) {
let node = new Node(value);
if (this.head === null) {
this.head = node;
this.tail = node;
} else {
this.tail.next = temp;
this.tail = temp;
}
this.size += 1;
}
insert(index, value) {
if (0 <= index <= this.size) {
let node = new Node(value);
let current = this.head;
let previous = new Node(next=current);
let count = 0;
while (count < index) {
previous = current;
current = current.next;
count += 1;
}
previous.next = node
node.next = current
if (previous.value === null) {
this.head = node;
}
if (node.next === null) {
this.tail = node;
}
this.size += 1
return true;
} else {
return false;
}
}
pop(index) {
if (0 <= index <= self.size && this.head === null) {
let current = this.head;
let previous = new Node(next=current);
let count = 0;
while (count < index) {
previous = current;
current = current.next;
count += 1;
}
previous.next = current.next;
if (previous.value === null) {
this.head = current.next;
}
if (current.next === null) {
this.tail = previous;
}
this.size -= 1;
return current.value;
} else {
return null;
}
}
remove(item) {
let found = false;
let current = this.head;
let previous = new Node(next=current);
let index = 0;
while (! found && current !== null) {
if (current.value === item) {
found = true;
} else {
previous = current;
current = current.next;
}
index += 1
}
if (found) {
previous.next = current.next;
if (previous.value === null) {
this.head = current.next;
}
if (current.next === null) {
this.tail = previous;
}
this.size -= 1;
return index;
} else {
return -1;
}
}
find(item) {
let current = this.head;
let count = 0;
while (current !== null) {
if (current.value === item) {
return count;
} else {
current = current.next;
count += 1;
}
}
return -1;
}
iter() {
let current = this.head;
while (current !== null) {
yield current.value;
current = current.next;
}
}
size() {
return this.size;
}
clear() {
this.head = null;
this.tail = null;
this.size = 0;
}
isEmpty() {
return this.size === 0;
}
}