首頁 > Java > java教程 > Java模擬單鍊錶和雙端鍊錶資料結構的實例講解

Java模擬單鍊錶和雙端鍊錶資料結構的實例講解

高洛峰
發布: 2017-01-24 16:05:44
原創
1615 人瀏覽過

模擬單鍊錶

線性表:
線性表(亦作順序表)是最基本、最簡單、也是最常用的一種資料結構。
線性表中資料元素之間的關係是一對一的關係,即除了第一個和最後一個資料元素之外,其它資料元素都是首尾相接的。
線性表的邏輯結構簡單,便於實作和操作。
在實際應用中,線性表都是以堆疊、佇列、字串等特殊線性表的形式來使用的。
線性結構的基本特徵為:
1.集合中必存在唯一的一個「第一元素」;
2.集合中必存在唯一的一個 「最後元素」 ;
3.除最後一個元素之外,均有 唯一的後繼(後件);
4.除第一個元素之外,均有 唯一的前驅(前件)。

鍊錶:linked list
鍊錶是一種實體儲存單元上非連續、非順序的儲存結構,資料元素的邏輯順序是透過鍊錶中的指標連結次序實現的
每個資料項都被包含在「鏈結點」(Link)中。
鏈結點是一個類別的對象,這類可稱為Link。鍊錶中有許多類似的鏈結點,每個Link中都包含有一個對下一個鏈結點引用的欄位next。
鍊錶物件本身保存了一個指向第一個鏈結點的引用first。 (若沒有first,則無法定位)
鍊錶不能像數組那樣(利用下標)直接存取到資料項,而需要用資料間的關係來定位,即存取鏈結點所引用的下一個鏈結點,而後再下一個,直到訪問到需要的資料
在鏈頭插入和刪除的時間複雜度為O(1),因為只需要改變引用的指向即可
而查找、刪除指定結點、在指定結點後插入,這些操作都需要平均都需要搜尋鍊錶中的一半結點,效率為O(N)。
單鍊錶:
以「結點的序列」表示線性表稱作線性鍊錶(單鍊錶)
是一種鍊式存取的資料結構,用一組位址任意的儲存單元存放線性表中的資料元素。 (這組儲存單元既可以是連續的,也可以是不連續的)
鏈結點的結構:

Java模擬單鍊錶和雙端鍊錶資料結構的實例講解

存放結點值的資料域data;存放結點的​​引用的指標域(鏈域)next
鍊錶透過每個結點的鏈域將線性表的n個結點按其邏輯順序連結在一起的。
每個結點只有一個鏈域的鍊錶稱為單鍊錶(Single Linked List) , 一個方向, 只有後繼結節的引用

/** 
 * 单链表:头插法 后进先出 
 * 将链表的左边称为链头,右边称为链尾。 
 * 头插法建单链表是将链表右端看成固定的,链表不断向左延伸而得到的。 
 * 头插法最先得到的是尾结点 
 * @author stone 
 */
public class SingleLinkedList<T> { 
    
  private Link<T> first;    //首结点 
  public SingleLinkedList() { 
      
  } 
    
  public boolean isEmpty() { 
    return first == null; 
  } 
    
  public void insertFirst(T data) {// 插入 到 链头 
    Link<T> newLink = new Link<T>(data); 
    newLink.next = first; //新结点的next指向上一结点 
    first = newLink; 
  } 
    
  public Link<T> deleteFirst() {//删除 链头 
    Link<T> temp = first; 
    first = first.next; //变更首结点,为下一结点 
    return temp; 
  } 
    
  public Link<T> find(T t) { 
    Link<T> find = first; 
    while (find != null) { 
      if (!find.data.equals(t)) { 
        find = find.next; 
      } else { 
        break; 
      } 
    } 
    return find; 
  } 
    
  public Link<T> delete(T t) { 
    if (isEmpty()) { 
      return null; 
    } else { 
      if (first.data.equals(t)) { 
        Link<T> temp = first; 
        first = first.next; //变更首结点,为下一结点 
        return temp; 
      } 
    } 
    Link<T> p = first; 
    Link<T> q = first; 
    while (!p.data.equals(t)) { 
      if (p.next == null) {//表示到链尾还没找到 
        return null; 
      } else { 
        q = p; 
        p = p.next; 
      } 
    } 
      
    q.next = p.next; 
    return p; 
  } 
    
  public void displayList() {//遍历 
    System.out.println("List (first-->last):"); 
    Link<T> current = first; 
    while (current != null) { 
      current.displayLink(); 
      current = current.next; 
    } 
  } 
    
  public void displayListReverse() {//反序遍历 
    Link<T> p = first, q = first.next, t; 
    while (q != null) {//指针反向,遍历的数据顺序向后 
      t = q.next; //no3 
      if (p == first) {// 当为原来的头时,头的.next应该置空 
        p.next = null; 
      } 
      q.next = p;// no3 -> no1 pointer reverse 
      p = q; //start is reverse 
      q = t; //no3 start 
    } 
    //上面循环中的if里,把first.next 置空了, 而当q为null不执行循环时,p就为原来的最且一个数据项,反转后把p赋给first 
    first = p;  
    displayList(); 
  } 
    
  class Link<T> {//链结点 
    T data;   //数据域 
    Link<T> next; //后继指针,结点    链域 
    Link(T data) { 
      this.data = data; 
    } 
    void displayLink() { 
      System.out.println("the data is " + data.toString()); 
    } 
  } 
    
  public static void main(String[] args) { 
    SingleLinkedList<Integer> list = new SingleLinkedList<Integer>(); 
    list.insertFirst(33); 
    list.insertFirst(78); 
    list.insertFirst(24); 
    list.insertFirst(22); 
    list.insertFirst(56); 
    list.displayList(); 
      
    list.deleteFirst(); 
    list.displayList(); 
      
    System.out.println("find:" + list.find(56)); 
    System.out.println("find:" + list.find(33)); 
      
    System.out.println("delete find:" + list.delete(99)); 
    System.out.println("delete find:" + list.delete(24)); 
    list.displayList(); 
    System.out.println("----reverse----"); 
    list.displayListReverse(); 
  } 
}
登入後複製

打印

List (first-->last):
the data is 56
the data is 22
the data is 24
the data is 78
the data is 33
List (first-->last):
the data is 22
the data is 24
the data is 78
the data is 33
find:null
find:linked_list.SingleLinkedList$Link@4b71bbc9
delete find:null
delete find:linked_list.SingleLinkedList$Link@17dfafd1
List (first-->last):
the data is 22
the data is 78
the data is 33
----reverse----
List (first-->last):
the data is 33
the data is 78
the data is 22
登入後複製

   

出 -若將鍊錶的左端固定,鍊錶不斷向右延伸,這種建立鍊錶的方法稱為尾插法。 

尾插法建立鍊錶時,頭指針固定不動,故必須設立一個尾部的指針,向鍊錶右邊延伸, 
尾插法最先得到的是頭結點。

public class SingleLinkedList2<T> {
    
  private Link<T> head;   //首结点
  public SingleLinkedList2() {
      
  }
    
  public boolean isEmpty() {
    return head == null;
  }
    
  public void insertLast(T data) {//在链尾 插入
    Link<T> newLink = new Link<T>(data);
    if (head != null) {
      Link<T> nextP = head.next;
      if (nextP == null) {
        head.next = newLink;
      } else {
        Link<T> rear = null;
        while (nextP != null) {
          rear = nextP;
          nextP = nextP.next;
        }
        rear.next = newLink;
      }
    } else {
      head = newLink;
    }
  }
    
  public Link<T> deleteLast() {//删除 链尾
    Link<T> p = head;
    Link<T> q = head;
    while (p.next != null) {// p的下一个结点不为空,q等于当前的p(即q是上一个,p是下一个) 循环结束时,q等于链尾倒数第二个
      q = p;
      p = p.next;
    }
    //delete
    q.next = null;
    return p;
  }
    
  public Link<T> find(T t) {
    Link<T> find = head;
    while (find != null) {
      if (!find.data.equals(t)) {
        find = find.next;
      } else {
        break;
      }
    }
    return find;
  }
    
  public Link<T> delete(T t) {
    if (isEmpty()) {
      return null;
    } else {
      if (head.data.equals(t)) {
        Link<T> temp = head;
        head = head.next; //变更首结点,为下一结点
        return temp;
      }
    }
    Link<T> p = head;
    Link<T> q = head;
    while (!p.data.equals(t)) {
      if (p.next == null) {//表示到链尾还没找到
        return null;
      } else {
        q = p;
        p = p.next;
      }
    }
      
    q.next = p.next;
    return p;
  }
    
  public void displayList() {//遍历
    System.out.println("List (head-->last):");
    Link<T> current = head;
    while (current != null) {
      current.displayLink();
      current = current.next;
    }
  }
    
  public void displayListReverse() {//反序遍历
    Link<T> p = head, q = head.next, t;
    while (q != null) {//指针反向,遍历的数据顺序向后
      t = q.next; //no3
      if (p == head) {// 当为原来的头时,头的.next应该置空
        p.next = null;
      }
      q.next = p;// no3 -> no1 pointer reverse
      p = q; //start is reverse
      q = t; //no3 start
    }
    //上面循环中的if里,把head.next 置空了, 而当q为null不执行循环时,p就为原来的最且一个数据项,反转后把p赋给head
    head = p; 
    displayList();
  }
    
  class Link<T> {//链结点
    T data;   //数据域
    Link<T> next; //后继指针,结点    链域
    Link(T data) {
      this.data = data;
    }
    void displayLink() {
      System.out.println("the data is " + data.toString());
    }
  }
    
  public static void main(String[] args) {
    SingleLinkedList2<Integer> list = new SingleLinkedList2<Integer>();
    list.insertLast(33);
    list.insertLast(78);
    list.insertLast(24);
    list.insertLast(22);
    list.insertLast(56);
    list.displayList();
      
    list.deleteLast();
    list.displayList();
      
    System.out.println("find:" + list.find(56));
    System.out.println("find:" + list.find(33));
      
    System.out.println("delete find:" + list.delete(99));
    System.out.println("delete find:" + list.delete(78));
    list.displayList();
    System.out.println("----reverse----");
    list.displayListReverse();
  }
}
登入後複製

   

列印

List (head-->last):
the data is 33
the data is 78
the data is 24
the data is 22
the data is 56
List (head-->last):
the data is 33
the data is 78
the data is 24
the data is 22
find:null
find:linked_list.SingleLinkedList2$Link@4b71bbc9
delete find:null
delete find:linked_list.SingleLinkedList2$Link@17dfafd1
List (head-->last):
the data is 33
the data is 24
the data is 22
----reverse----
List (head-->last):
the data is 22
the data is 24
the data is 33
登入後複製

   

模擬雙端鍊錶,以鍊錶實現了一個傳統和佇列對錶端的雙端鍊端?最後一個鏈結點的引用rear

這樣在鏈尾插入會變得非常容易,只需改變rear的next為新增的結點即可,而不需要循環搜索到最後一個節點
所以有insertFirst、insertLast
刪除鏈頭時,只需要改變引用指向即可;刪除鏈尾時,需要將倒數第二個結點的next置空,
而沒有一個引用是指向它的,所以還是需要循環來讀取操作

/**
 * 双端链表
 * @author stone
 */
public class TwoEndpointList<T> {
  private Link<T> head;   //首结点
  private Link<T> rear;   //尾部指针
    
  public TwoEndpointList() {
      
  }
    
  public T peekHead() {
    if (head != null) {
      return head.data;
    }
    return null;
  }
    
  public boolean isEmpty() {
    return head == null;
  }
    
  public void insertFirst(T data) {// 插入 到 链头
    Link<T> newLink = new Link<T>(data);
    newLink.next = head; //新结点的next指向上一结点
    head = newLink;
  }
    
  public void insertLast(T data) {//在链尾 插入
    Link<T> newLink = new Link<T>(data);
    if (head == null) {
      rear = null;
    }
    if (rear != null) {
      rear.next = newLink;
    } else {
      head = newLink;
      head.next = rear;
    }
    rear = newLink; //下次插入时,从rear处插入
      
  }
    
  public T deleteHead() {//删除 链头
    if (isEmpty()) return null;
    Link<T> temp = head;
    head = head.next; //变更首结点,为下一结点
    if (head == null) {
    <span style="white-space:pre">  </span>rear = head;
    }
    return temp.data;
  }
    
  public T find(T t) {
    if (isEmpty()) {
      return null;
    }
    Link<T> find = head;
    while (find != null) {
      if (!find.data.equals(t)) {
        find = find.next;
      } else {
        break;
      }
    }
    if (find == null) {
      return null;
    }
    return find.data;
  }
    
  public T delete(T t) {
    if (isEmpty()) {
      return null;
    } else {
      if (head.data.equals(t)) {
        Link<T> temp = head;
        head = head.next; //变更首结点,为下一结点
        return temp.data;
      }
    }
    Link<T> p = head;
    Link<T> q = head;
    while (!p.data.equals(t)) {
      if (p.next == null) {//表示到链尾还没找到
        return null;
      } else {
        q = p;
        p = p.next;
      }
    }
    q.next = p.next;
    return p.data;
  }
    
  public void displayList() {//遍历
    System.out.println("List (head-->last):");
    Link<T> current = head;
    while (current != null) {
      current.displayLink();
      current = current.next;
    }
  }
    
  public void displayListReverse() {//反序遍历
    if (isEmpty()) {
      return;
    }
    Link<T> p = head, q = head.next, t;
    while (q != null) {//指针反向,遍历的数据顺序向后
      t = q.next; //no3
      if (p == head) {// 当为原来的头时,头的.next应该置空
        p.next = null;
      }
      q.next = p;// no3 -> no1 pointer reverse
      p = q; //start is reverse
      q = t; //no3 start
    }
    //上面循环中的if里,把head.next 置空了, 而当q为null不执行循环时,p就为原来的最且一个数据项,反转后把p赋给head
    head = p; 
    displayList();
  }
    
  class Link<T> {//链结点
    T data;   //数据域
    Link<T> next; //后继指针,结点    链域
    Link(T data) {
      this.data = data;
    }
    void displayLink() {
      System.out.println("the data is " + data.toString());
    }
  }
    
  public static void main(String[] args) {
    TwoEndpointList<Integer> list = new TwoEndpointList<Integer>();
    list.insertLast(1);
    list.insertFirst(2);
    list.insertLast(3);
    list.insertFirst(4);
    list.insertLast(5);
    list.displayList();
      
    list.deleteHead();
    list.displayList();
      
    System.out.println("find:" + list.find(6));
    System.out.println("find:" + list.find(3));
  
    System.out.println("delete find:" + list.delete(6));
    System.out.println("delete find:" + list.delete(5));
    list.displayList();
    System.out.println("----reverse----");
    list.displayListReverse();
  }
}
登入後複製

   

打印

List (head-->last):
the data is 4
the data is 2
the data is 1
the data is 3
the data is 5
List (head-->last):
the data is 2
the data is 1
the data is 3
the data is 5
find:null
find:3
delete find:null
delete find:5
List (head-->last):
the data is 2
the data is 1
the data is 3
----reverse----
List (head-->last):
the data is 3
the data is 1
the data is 2
登入後複製

   

使用鍊錶實現🜠o🜚

印刷

public class LinkStack<T> {
  private TwoEndpointList<T> datas;
    
  public LinkStack() {
    datas = new TwoEndpointList<T>();
  }
    
  // 入栈
  public void push(T data) {
    datas.insertFirst(data);
  }
    
  // 出栈
  public T pop() {
    return datas.deleteHead();
  }
    
  // 查看栈顶
  public T peek() {
    return datas.peekHead();
  }
    
  //栈是否为空
  public boolean isEmpty() {
    return datas.isEmpty();
  }
    
  public static void main(String[] args) {
    LinkStack<Integer> stack = new LinkStack<Integer>();
    for (int i = 0; i < 5; i++) {
      stack.push(i);
    }
    for (int i = 0; i < 5; i++) {
      Integer peek = stack.peek();
      System.out.println("peek:" + peek);
    }
    for (int i = 0; i < 6; i++) {
      Integer pop = stack.pop();
      System.out.println("pop:" + pop);
    }
      
    System.out.println("----");
    for (int i = 5; i > 0; i--) {
      stack.push(i);
    }
    for (int i = 5; i > 0; i--) {
      Integer peek = stack.peek();
      System.out.println("peek:" + peek);
    }
    for (int i = 5; i > 0; i--) {
      Integer pop = stack.pop();
      System.out.println("pop:" + pop);
    }
  }
}
登入後複製

   由

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板