基本概念
線性表是一種邏輯結構,相同數據類型的n個數據元素的有限序列,除第一個元素外,每個元素有且僅有一個直接前驅,除最後一個元素外,每個元素有且僅有一個直接後繼。
線性表具有以下特點:
- 元素個數有限
- 邏輯上元素有先後次序
- 數據類型相同
- 僅討論元素間的邏輯關係
數組和鏈表
數組的優點
- 隨機訪問性強
- 查找速度快
數組的缺點
- 插入和刪除效率低
- 可能浪費內存
- 內存要求高,必須有連續的內存空間
- 數組大小固定,不能動態擴展
鏈表的優點
- 插入刪除速度快
- 內存利用率高,不會浪費內存
- 大小內有固定,拓展很靈活
鏈表的缺點
- 不能隨機查找,必須從第一個開始遍歷,查找效率低
操作效率
操作 | 數組 | 鏈表 |
---|---|---|
讀取 | O(1) | O(N) |
插入 | O(n) | O(1) |
刪除 | O(n) | O(1) |
單鏈表、雙鏈表、循環鏈表
單鏈表
雙鏈表
循環鏈表
- 循環單鏈表
與單鏈表的區別在於,表中最後一個節點的指針不爲null,而改爲指向頭結點(第一個節點),從而整個鏈表形成一個環。判斷循環單鏈表是否爲空,判斷是否等於頭指針。只有一個尾指針的循環單鏈表,可以很方便的操作表頭和表尾,因爲尾指針的後繼就是頭指針O(1) 。 - 循環雙鏈表
與雙鏈表的區別在於,頭結點的prior指針指向尾節點,尾節點的next指針指向頭結點。
基本操作
- 頭節點插入
- 尾節點插入
- 插入
- 刪除
基本操作實戰
數據結構存儲類 ListNode.java
public class ListNode {
public int value;
public ListNode next;
public ListNode(int value) {
this.value = value;
}
}
操作方法類 MyList.java
public class MyList {
/**
* 頭節點插入
* @param head
* @param newNode
*/
public static void headInsert(ListNode head, ListNode newNode) {
newNode.next = head;
}
/**
* 尾節點插入
* @param tail
* @param newNode
*/
public static void tailInsert(ListNode tail, ListNode newNode) {
tail.next = newNode;
}
/**
* 遍歷
* @param head
*/
public static void traverse(ListNode head) {
while (head != null) {
System.out.print(head.value + " ");
head = head.next;
}
}
/**
* 查找
* @param head
* @param value
* @return
*/
public static int find(ListNode head, int value) {
int index = -1;
int count = 0;
while (head != null) {
if (value == head.value) {
index = count;
break;
}
head = head.next;
count ++;
}
return index;
}
/**
* 插入
* @param p
* @param s
*/
public static void insert(ListNode p, ListNode s) {
ListNode next = p.next;
p.next = s;
s.next = next;
}
/**
* 刪除
* @param head
* @param q
*/
public static void delete(ListNode head, ListNode q) {
if (q.next != null) {
ListNode next = q.next;
q.value = next.value;
q.next = next.next;
next = null;
} else {
while (head != null) {
if (head.next == q) {
head.next = null;
q = null;
break;
}
head = head.next;
}
}
}
public static void main(String[] args) {
ListNode node1 = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode node4 = new ListNode(4);
node1.next = node2;
node2.next = node3;
node3.next = node4;
//頭節點插入
ListNode node0 = new ListNode(0);
headInsert(node1, node0);
System.out.print("頭節點插入 :");
traverse(node0);
System.out.println();
//尾節點插入
ListNode node5 = new ListNode(5);
tailInsert(node4, node5);
System.out.print("尾節點插入 :");
traverse(node0);
System.out.println();
//遍歷
System.out.print("遍歷 :");
traverse(node0);
System.out.println();
//查找
int index = find(node0, 4);
System.out.print("查找結果位置:" + index);
//插入
ListNode node6 = new ListNode(6);
insert(node2, node6);
System.out.println();
//遍歷
System.out.print("插入之後遍歷 :");
traverse(node0);
//刪除
delete(node0, node6);
System.out.println();
System.out.print("刪除之後遍歷 :");
traverse(node0);
//刪除
delete(node0, node3);
System.out.println();
System.out.print("刪除之後遍歷 :");
traverse(node0);
}
}