單鏈表中結點類型的描述如下:
class LNode {
Integer data;
LNode next;
}
1.頭插法建立單鏈表。
從一個空表開始,生成新節點,並將讀取到的數據存放到新節點的數據域中,然後將新節點插入到當前鏈表的表頭,即頭結點之後,如圖所示:
算法如下:
public LNode createList1() {
LNode l = new LNode();
l.next = null;
for(int i=0; i<10; i++) {
LNode tmp = new LNode();
tmp.data = i;
tmp.next = l.next;
l.next = tmp;
}
return l;
}
2.尾插法建立單鏈表
將新節點插入到當前鏈表的表尾,爲此增加一個尾指針r,使其指向當前鏈表的表尾,如圖:
算法如下:
public LNode createList2() {
LNode l = new LNode();
LNode r = l;
for(int i=0; i<10; i++) {
LNode tmp = new LNode();
tmp.data = i;
r.next = tmp;
r = tmp;
}
r.next = null;
return l;
}
3.按序號查找節點值。
在單鏈表中從第一個節點出發,順指針next域住個往下搜索,直到找到第i個節點爲止,否則返回最後一個節點指針域NULL。
public LNode getElem(LNode l, int i) {
if(i < 1) { //如果要查找的元素的位置比1還小,返回NUll
return null;
}
int j = 1;
LNode p = l.next;
while(null != p && j < i) { //從第一個節點開始查找,查找第i個節點
p = p.next;
j++;
}
return p; //返回第i個節點的指針,如果i大於表長,p=NULL
}
4.按值查找表節點
從單鏈表第一個節點開始,由前往後依次比較表中各節點數據域的值,若某節點數據域的值等於給定值e,則返回該節點指針,若整個單鏈表中沒有這樣的節點,則返回NULL。
public LNode locateElem(LNode l, int e) {
LNode p = l.next;
while(null != p && e != p.data) {
p = p.next;
}
return p;
}
5.插入節點操作
插入操作是將值爲x的新節點插入到單鏈表的第i個位置。首先檢查插入位置的合理性,然後找到待插入位置的前驅節點,即第i-1個元素,再在其後面插入新的節點。
算法首先調用getElem(LNode l)
方法查找第i-1個節點,假設返回的第i-1個節點爲p, 然後令新節點s的指針指向p的後繼節點,再令節點p的指針域指向新插入的節點s,如圖所示:
(1) p = getElem(l, i-1);
(2) s.next = p.next;
(3) p.next = s;
本算法主要開銷在查找第i-1個元素,時間複雜度爲O(n)。
此外,可以採用另一種方式將其轉換爲後插操作來實現,設帶插入節點爲s,將s插入到p的前面。我們採用將s插入到p的後面的方式,然後將p.data與s.data交換即可,這樣既能滿足邏輯關係,又能使得時間複雜度爲O(1),思想如下:
s.next = p.next;
p.next = s;
temp = p.data;
p.data = s.data;
s.data = temp;
6.刪除節點元素
刪除操作是將單鏈表的第i個節點刪除,先檢查其刪除位置的合法性,然後查找表中第i-1個節點,即被刪除節點的前驅節點,再將其刪除,如下圖所示:
假設節點p爲找到的被刪除節點的前驅節點,爲了實現這一操作後的邏輯關係的變化,僅需要修改p的指針域,即將p的指針域next指向q的下一個節點。
代碼片段如下:
p = getElem(l, i-1);
q = p.next;
p.next = q.next;
q.next = null;
和插入算法一樣,時間主要消耗在查找操作上,時間複雜度爲O(n)。
其實,刪除節點p的操作可以用刪除p的後繼節點操作來實現,實質就是將其後繼節點的值賦予其自身,然後刪除後繼節點,使得時間複雜度爲O(1)。
q = p.next;
p.data = q.data; //將後繼元素的值賦予該元素
p.next = q.next;
q.next = null;