目錄
一、鍊錶的特點
二、虛擬頭結點
三、鍊錶的實現
1、定義linkedlist
2、 構造方法
3、基本方法
4、新增元素
5、查詢元素
6、修改元素
7、刪除元素
鍊錶是一種物理儲存單元上非連續、非順序的資料結構。前幾篇我們講到的陣列也好,基於陣列實現的棧和佇列也好,都是靜態的資料結構,都需要處理容量的問題。而鍊錶是真正的動態資料結構,也是最簡單的動態資料結構。
簡單的總結一下鍊錶的一些概念和特點:
(1)鍊錶是由0或多個結點構成的
(2)除頭結點外,每個結點都有乙個前驅結點
(3)除尾結點外,每個結點都有乙個後繼結點
為了後面自定義鍊錶方便,在這裡提及乙個概念:虛擬頭結點。啥意思呢,我們從鍊錶的特點中知道,頭結點是沒有前驅結點的,那在定義鍊錶時,需要對頭結點特殊處理。因此,為了後面實現鍊錶時免去這個煩惱,我們可以給鍊錶設定乙個假的頭結點,這個頭結點是空的,稱為虛擬頭結點,它的後繼結點是真正的頭結點。
沒有虛擬頭結點的鍊錶:
有虛擬頭結點的鍊錶:
前幾篇文章我們手動封裝實現了動態陣列,並且基於動態陣列實現了棧和佇列。這篇文章也一樣,我們在了解了鍊錶的特點後,也手動去實現乙個鍊錶。
public class linkedlist
public node(e e)
public node() }}
上面我們說到虛擬頭結點這個概念,在構造方法中,我們建立虛擬頭結點,如下:
private node dummyhead;
private int size;
public linkedlist()
仍然提供幾個基本方法,獲取當前鍊錶中結點個數、判斷鍊錶是否為空。如下:
public int getsize()
//是否為空
public boolean isempty()
向鍊錶中新增乙個結點,其實就是找到要插入位置的前驅結點(prev),把插入結點(node)的後繼結點指向前驅結點(prev)的後繼結點,把前驅結點(prev)的後繼結點指向要插入的結點(node)。
例如,我們要把666這個元素插入到0,1,2,3,4這樣乙個鍊錶中index為2的位置。那麼,只需要把666這個結點的後繼指向2,把1這個結點的後繼指向666,如下圖所示:
反過來可以嗎?先把1這個結點的後繼指向666,再把666這個結點的後繼指向2。當然是不可以的。把1的後繼指向666後,那麼1和2的連線已經斷開了,而666和2也沒有任何連線。那麼,當我們再把666的後繼指向2時,就無法做到了。以下是**實現:
//index位置處新增新元素
public void add(int index, e e)
node prev = dummyhead;
// 遍歷,找到要插入index的前驅
for (int i = 0; i < index; i++)
//node node = new node(e);
= prev.next;
= node;
// 上面三句**可以簡化為下面一句
prev.next = new node(e, prev.next);
size++;
}
從鍊錶中查詢第index的元素,實現起來並不複雜:從0開始,遍歷到index為止,最後輸出當前結點。查詢鍊錶中是否含有某個元素e,實現起來也很簡單。**如下:
//獲得第index個元素
public e get(int index)
node cur = dummyhead.next;
for (int i = 0; i < index; i++)
return cur.e;
}//查詢鍊錶中是否有元素e
public boolean contains(e e)
}return false;
}
修改鍊錶中的元素,實現起來也很簡單:從0遍歷鍊錶,到index停止。把當前結點的元素修改即可。**如下:
//修改第index個元素
public void set(int index, e e)
node cur = dummyhead.next;
for (int i = 0; i < index; i++)
cur.e = e;
}
那麼,如何從鍊錶中刪除乙個結點呢?從0開始遍歷,到index為止,找到index的前驅。新建乙個結點,指向前驅的後繼結點。前驅的後繼結點指向新建結點的後繼,最後把新建結點指向null,刪除這個結點。**如下:
// 刪除元素
public e remove(int index)
node prev = dummyhead;
for (int i = 0; i < index; i++)
node retnode = prev.next;
prev.next = retnode.next;
retnode.next = null;
size--;
return retnode.e;
}
經過上面一系列的步驟,我們實現了鍊錶,那麼我們是否可以基於鍊錶實現棧和佇列?當然是可以的。而且,實現起來非常簡單。只要我們還記得棧和佇列的特點,那麼基於鍊錶實現棧和佇列其實不是很困難,在這裡就不去手動實現了。 資料結構 表之煉表
頭插法建立 尾插法建立 顯示 銷毀 include include using namespace std typedef int elemtype typedef struct lnode linklist void createlinklistf linklist l,elemtype a,in...
資料結構之鍊錶
頭結點 第乙個有效結點之前的那個結點 頭結點並不存有效資料 加頭結點的目的主要是為了方便對鍊錶的操作 頭指標 指向頭結點的指標變數 尾指標 指向尾節點的指標變數 如果希望通過乙個函式對鍊錶進行處理,只需要乙個引數 頭指標 首先要定義乙個單鏈表儲存結構 然後建立乙個空表,即初始化,我寫的這個提前設定好...
資料結構之鍊錶
鍊錶是一種基本的資料結構型別,它由乙個個結點組成。每乙個結點包括乙個資料的儲存和乙個指向下乙個結點的引用。在這個定義中,結點是乙個可能含有任意型別資料的抽象實體,它所包含的指向結點的應用顯示了它在構造鍊錶之中的作用。和遞迴程式一樣,遞迴資料結構的概念一開始也令人費解,但其實它的簡潔性賦予了它巨大的價...