Java學習筆記:資料結構之線性表(雙向連結串列)
目錄
文章目錄
Java資料結構之線性表
連結串列結構
鏈式儲存結構是基於指標實現,我們把一個資料元素和一個指標成為節點
鏈式儲存結構是用指標把相互直接關聯的結點(即直接前驅節點或直接後繼節點)連結起來。 鏈式儲存結構的線性表成為連結串列
連結串列型別
根據連結串列的構造方式的不同可以分為:
1. 單向連結串列
2. 迴圈連結串列
3. 雙向連結串列
線性表的抽象資料型別
1、線性表的置空操作 | clear() |
2、線性表判空操作: | isEmpty() |
3、求線性表的長度: | size( ) |
4、取元素操作: | get( i ) |
5、插入操作: | insert( i, x ) |
6、刪除操作: | delete( i) |
雙向連結串列
1、基本概念
雙向連結串列也叫雙連結串列,是連結串列的一種,它的每個資料結點中都有兩個指標,分別指向直接後繼和直接前驅。所以,從雙向連結串列中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。一般我們都構造雙向迴圈連結串列。
2、圖形理解
相對於單連結串列而言,每個節點不僅有一個next,而且有一個指向前一個元素的pre
3、連結串列特性
每個資料結點中都有兩個指標,分別指向直接後繼和直接前驅
4、優缺點
優點
可以找到前驅和後繼,可進可退
缺點
增加刪除節點複雜,多需要分配一個指標儲存空間
優缺點總結
適用於需要雙向查詢節點值的情況
5、程式碼展示
5.1、基礎程式碼
/** 儲存該連結串列的頭結點 */
private Node head;
/** 儲存該連結串列的尾結點 */
private Node tail;
/** 儲存該連結串列中已包含的節點數 */
private int size;
/** 內部類 */
private class Node {
// 儲存節點資料
private T data;
// 指向上個節點的引用
private Node prev;
// 指向下個節點的引用
private Node next;
// 無參構造器
public Node() {
}
// 初始化構造器
public Node(T data) {
this.data = data;
}
public Node(T data, Node prev) {
this.data = data;
this.prev = prev;
}
public Node(T data, Node prev, Node next) {
this.data = data;
this.prev = prev;
this.next = next;
}
}
5.2、插入資料
a、連結串列為空時
/**
* <p>以指定資料元素來建立連結串列,Ps.(當前連結串列為空)</p>
*
* @param element 資料
* @author Kallen
* @since 2020/12/23 13:33
*/
public DoubleLink(T element) {
head = new Node(element);
tail = head;
size++;
}
b、根據索引新增
/**
* <p>根據索引插入元素</p>
*
* @param element 元素
* @param index 索引
* @author Kallen
* @since 2020/12/28 16:05
*/
public void insert(T element, int index) {
if (index < 0 || index > size - 1) {
throw new IndexOutOfBoundsException("索引越界");
}
// 判斷當前連結串列是否為空
if (head == null) {
DoubleLink(element);
}else {
if (index == 0) {
// 當index為0時,即為在連結串列頭插入
addAtHeader(element);
}else {
// 獲取插入點的前一個節點
Node prev = getNodeByIndex(index - 1);
// 獲取插入點的節點
Node next = prev.next;
// 讓新節點的next引用指向next節點,prev引用指向prev節點
Node newNode = new Node(element , prev , next);
// 讓prev的next指向新節點。
prev.next = newNode;
// 讓prev的下一個節點的prev指向新節點
next.prev = newNode;
size++;
}
}
}
c、尾插法
/**
* <p>尾插法</p>
*
* @param element 元素
* @author Kallen
* @since 2020/12/28 16:25
*/
public void add(T element) {
// 如果該連結串列為空
if (head == null) {
DoubleLink(element);
}else {
// 建立新節點,新節點的pre引用指向原tail節點
Node newNode = new Node(element , tail , null);
// 讓尾節點的next指向新增的節點
tail.next = newNode;
// 以新節點作為新的尾節點
tail = newNode;
}
size++;
}
d、頭插法
/**
* <p>頭插法</p>
*
* @param element 元素
* @author Kallen
* @since 2020/12/28 16:10
*/
public void addAtHeader(T element) {
// 建立新節點,讓新節點的next指向原來的head,並以新節點作為新的head
head = new Node(element, head);
// 如果插入之前是空連結串列
if (tail == null)
{
tail = head;
}
size++;
}
5.3、查詢資料
a、根據索引查詢
/**
* <p>獲取指定索引處的元素</p>
*
* @param index 指定索引
* @return {@link T} 元素
* @author Kallen
* @since 2020/12/23 13:35
*/
public T get(int index) {
return getNodeByIndex(index).data;
}
b、根據指定元素查詢索引
/**
* <p>查詢指定元素的索引</p>
*
* @param element 元素
* @return {@link int} 索引
* @author Kallen
* @since 2020/12/25 15:48
*/
public int locate(T element) {
Node current = head;
for (int i = 0; i < size && current != null; i++, current = current.next) {
if (current.data.equals(element)) {
return i;
}
}
return -1;
}
c、獲取當前連結串列長度
/**
* <p>獲取連結串列長度</p>
*
* @return {@link int} 連結串列長度
* @author Kallen
* @since 2020/12/23 13:34
*/
public int size() {
return size;
}
5.4、刪除資料
a、根據索引刪除
/**
* <p>根據索引刪除</p>
*
* @param index 索引
* @author Kallen
* @since 2020/12/28 17:08
*/
public void delete(int index) {
if (index < 0 || index > size - 1) {
throw new IndexOutOfBoundsException("索引越界");
}
if (index == 0) {
head = head.next;
head.prev = null;
}else {
// 獲取刪除節點的前一個節點
Node prev = getNodeByIndex(index-1);
// 讓prev節點的next指向被刪除節點的next
prev.next = prev.next.next;
// 讓被刪除節點的next節點的prev指向prev節點 Ps(被刪除節點的next節點不為尾節點)
if (prev.next != null) {
prev.next.prev = prev;
}
// 將被刪除節點的prev、next引用賦為null
prev.next.prev = null;
prev.next.next = null;
}
size--;
}
b、刪除最後一個元素
/**
* <p>刪除連結串列的最後一個元素</p>
*
* @author Kallen
* @since 2020/12/28 17:15
*/
public void remove() {
delete(size-1);
}
5.5、判斷是否為空
/**
* <p>判斷連結串列是否為空連結串列</p>
*
* @author Kallen
* @since 2020/12/28 17:16
*/
public boolean isEmpty() {
return size == 0;
}
5.6、清空連結串列
/**
* <p>清空連結串列</p>
*
* @author Kallen
* @since 2020/12/28 17:17
*/
public void clear() {
head = null;
tail = null;
size = 0;
}
5.7、私有方法
/**
* <p>根據指定索引獲取結點</p>
*
* @param index 索引
* @return {@link DoubleLink<T>.Node} 節點
* @author Kallen
* @since 2020/12/23 13:36
*/
private Node getNodeByIndex(int index) {
if (index < 0 || index > size - 1) {
throw new IndexOutOfBoundsException("索引越界");
}
// 當索引值小於該連結串列長度的一半時,應從頭結點開始搜尋,PS(值相同從頭結點開始搜尋)
if (index <= size / 2) {
Node current = head;
for (int i = 0; i <= size / 2 && current != null; i++, current = current.next) {
if (i == index) {
return current;
}
}
}else {
// 從tail節點開始搜尋
Node current = tail;
for (int i = size - 1; i > size / 2 && current != null; i++, current = current.prev) {
if (i == index) {
return current;
}
}
}
return null;
}
相關文章
- 【資料結構與演算法學習】線性表(順序表、單連結串列、雙向連結串列、迴圈連結串列)資料結構演算法
- 資料結構與演算法(三) -- 線性表之雙向連結串列資料結構演算法
- 資料結構之雙向連結串列資料結構
- LVGL雙向連結串列學習筆記筆記
- 資料結構實驗之連結串列九:雙向連結串列資料結構
- 資料結構-線性表、連結串列資料結構
- 資料結構——雙向連結串列資料結構
- 資料結構--陣列、單向連結串列、雙向連結串列資料結構陣列
- 【資料結構】線性表-單連結串列資料結構
- 畫江湖之資料結構【第一話:連結串列】雙向連結串列資料結構
- 畫江湖之資料結構 [第一話:連結串列] 雙向連結串列資料結構
- c/c++ 線性表之雙向迴圈連結串列C++
- 資料結構與演算法(二) -- 線性表之單向迴圈連結串列資料結構演算法
- React學習筆記之雙向資料繫結React筆記
- 資料結構(雙向連結串列的實現)資料結構
- 資料結構-雙向連結串列(Python實現)資料結構Python
- 前端資料結構--線性結構-連結串列前端資料結構
- JAVA資料結構之連結串列Java資料結構
- 資料結構-單連結串列、雙連結串列資料結構
- 線性表__資料結構筆記資料結構筆記
- 資料結構與演算法 | 線性表 —— 連結串列資料結構演算法
- 資料結構學習--連結串列資料結構
- c/c++ 線性表之單向連結串列C++
- 連結串列-雙向連結串列
- 資料結構與演算法-線性表-單連結串列資料結構演算法
- 資料結構筆記——線性表(下)資料結構筆記
- 資料結構筆記——線性表(中)資料結構筆記
- 資料結構基礎學習之線性表資料結構
- 資料結構與演算法——連結串列 Linked List(單連結串列、雙向連結串列、單向環形連結串列-Josephu 問題)資料結構演算法
- 畫江湖之資料結構【第一話:連結串列】單向連結串列資料結構
- 畫江湖之資料結構 [第一話:連結串列] 單向連結串列資料結構
- 連結串列-雙向通用連結串列
- 線性表——連結串列
- 資料結構之php實現單向連結串列資料結構PHP
- 結構與演算法(03):單向連結串列和雙向連結串列演算法
- 資料結構之「連結串列」資料結構
- 資料結構之連結串列資料結構
- java實現雙向連結串列Java