線性鏈表——雙向鏈表
雙向鏈表定義:
雙向鏈表(double linked list): 是在單表單的每個結點中,再設置一個指向前驅結點的指針域。因此,在雙向鏈表中的結點都有兩個指針域,一個指向前驅,一個指向后繼。
雙向鏈表的存儲結構
typedef struts DulNode{
Element data;
Struct DulNode *prior;前驅指針
Struct DulNode *next;后繼指針
}DulDouble, *DulLinkList;
雙向鏈表的插入與刪除
雙向鏈表的插入:
假設結點為s,要將結點插入到結點p和p->next中,我們需要下面幾步:
s.prev = p;
s.next = p.next;
p.next.prev = s;
p.next = s;
總結起來就是:先搞定s的前驅后繼,再搞定后結點的前驅,最后解決前驅結點的后繼
雙向鏈表的刪除:
要刪除p結點,只需要兩個步驟:
p.next.prev = p.prev;
p.prev.next = p.next;
free(p);
總結:
相對於單鏈表,雙向鏈表多了一個指針域,空間上要占用略多一點,但它有很好的對稱性,使得對某個結點的前后結點操作更容易,可以提高算法的時間性能,這是犧牲空間換取的。
Java程序實現雙鏈表:
package com.aclie.dataStructe4.sqeList; public class MyDoubleLinkList { private int length =0;//當前長度 private Node head;//頭結點 private Node tail;//當前結點結點 public MyDoubleLinkList(){ initLink(); } public void initLink(){ head = new Node(null); tail = new Node(null); this.head = tail; length++; } //獲取鏈表長度 public int getSize(){ return length; } //判斷鏈表是否為空 public boolean getEmpty(){ return getSize()==0; } //根據索引查找元素 從第一個有效值開始 public Node getNode(int index){ Node p; if(index < 0 || index > length ){ System.out.println("參數錯誤"); } if(index < this.length/2){ p = this.head; for(int i=0; i<index; i++){ p = p.next; } }else{ p = this.tail; for(int i= length; i>index;i--){ p = p.prev; } } return p; } public Object getData(int index){ return getNode(index).data; } //在頭結點處插入 public boolean addHead(Object e){ //前驅引用為null,后繼為node Node node = new Node(e, null, this.head); //改變頭結點的前驅后繼 this.head.prev = node; this.head = node; if(tail == null){ tail = this.head; } length++; return true; } //在尾結點插入 public boolean addTail(Object e){ if(this.head == null){ this.head = new Node(e,null,null); this.tail = this.head; }else{ Node node = new Node(e,this.tail,null); this.tail.next = node; this.tail = node; } length++; return true; } //在指定位置插入元素 public boolean addData(int index,Object ele){ if(index <0 || index > this.length){ System.out.println("參數錯誤"); } if(this.head == null){ this.addTail(ele);//用尾插法 }else{ if(index == 0){ addHead(ele);//用頭插法 }else{ Node p = this.getNode(index);//要插入處的結點 Node n = p.next; Node node = new Node(ele,p,n);//要插入的結點 n.prev = node; p.next = node; length ++; } } return true; } public void removeData(int index){ if(index < 0 || index > length){ System.out.println("參數錯誤"); }else{ Node del = null; if(index == 0){ del = this.head; this.head = this.head.next; this.head.prev = null; length--; }else if(index == (length-1)){ Node p = this.getNode(index-1);//得到要刪除結點的前驅結點 del = p.next;//要刪除的結點 p.next = del.next; if(del.next != null){ del.next.prev = p; } del.next = null; del.prev = null; length --; this.tail.next = null; this.tail.prev = p; this.tail = p; } else{ Node p = this.getNode(index-1);//要刪除結點的前驅結點 del = p.next;//要刪除的結點 p.next = del.next; if(del.next != null){ del.next.prev = p; } del.prev = null; del.next = null; length--; } } } //打印所有鏈表中的元素 public void print(){ Node current = this.head; while(current != null){ System.out.println(current.data); current = current.next; } } //反向打印鏈表 public void reversePrint(){ Node current = this.tail; while(current != null){ System.out.println(current.data); current = current.prev; } } public static void main(String args[]){ MyDoubleLinkList linkList = new MyDoubleLinkList(); linkList.addHead("aaaa"); // System.out.println(linkList.getData(1)); linkList.addTail("bbbb"); // System.out.println(linkList.getData(3)); linkList.addData(2, "eeee"); // linkList.print(); linkList.removeData(2); linkList.print(); System.out.println("....."); linkList.reversePrint(); } } class Node{ Node prev;//指針域中前驅 Node next;//指針域中后繼 Object data;//數據域 public Node(Node current){ prev = current; next = current; } //雙鏈表前驅后繼及數字域 public Node(Object d, Node p,Node n){ this.data = d; this.prev = p; this.next = n; } public Node getPrev() { return prev; } public void setPrev(Node prev) { this.prev = prev; } public Node getNext() { return next; } public void setNext(Node next) { this.next = next; } }