天天看點

資料結構之連結清單實作

分析:

  1. 連結清單(Linked list)是一種常見的基礎資料結構,是一種線性表,但是并不會按線性的順序存儲資料,而是在每一個節點裡存到下一個節點的指針(Pointer)。
  2. 單連結清單是連結清單中結構最簡單的。一個單連結清單的節點(Node)分為兩個部分,一個是資料域,一個是節點域。
  3. 雙向連結清單可以從兩個方向周遊

1. 單向連結清單

1)定義一個節點

class Node<E> {

    E e;
    Node<E> next;
    public Node(E e,Node<E> next){
        this.e = e;
        this.next = next;
    }

    public Node(E e){
        this(e,null);
    }
}
           

2)構造函數

//虛拟頭節點
private Node<E> dummyHead;
private int size;
public LinkedList(){
    dummyHead = new Node<>(null,null);
    size = ;
}
           

3)添加元素

//1->2->3->4
//1. 首先找到要插入位置的前節點
//2. 比如你要在index=2位置插入66,你就把要插入的66節點的next指向3,2的next節點指向66,然後就插入進去了
public void add(int index, E e){

    Node<E> pre = dummyHead;
    for (int i = ; i < index; i++)
        pre = pre.next;
    Node<E> node = new Node<>(e);
    //目前待插入節點的next用待插入節點的前一個節點的next指向
    node.next = pre.next;
    //前一個節點的next指向目前節點就對了
    pre.next = node;
    size++;
}

public void addFirst(E e){
    add(,e);
}

public void addLast(E e){
    add(size,e);
}
           

3)擷取資料

擷取資料就是擷取某一個位置的節點,然後就能擷取這個節點的資料了
public E get(int index){
    if(index <  || index > size){
        throw new IllegalArgumentException("角标不合法");
    }
    Node<E> current = dummyHead.next;
    for (int i = ; i < index; i++) {
        current = current.next;
    }
    return current.e;
}

public E getFirst(){
    return get();
}

public E getLast(){
    return get(size - );
}
           

4)修改資料

//首先找到要修改的index節點,然後直接修改
public void set(int index, E e){
    if(index <  || index > size){
        throw new IllegalArgumentException("角标不合法");
    }
    Node<E> current = dummyHead.next;
    for (int i = ; i < index; i++) {
        current = current.next;
    }
    current.e = e;
}
           

5) 删除資料

//1->2->3->4
//假設我要删除2這個節點 我就應該找到它的前一個節點1,然後
//用1這個節點指向要删除節點的下一個節點,即3,删除節點的next=null
public E remove(int index){
    Node<E> pre = dummyHead;
    for (int i = ; i < index; i++) {
        pre = pre.next;
    }
    if(pre == null)
        return null;
    Node<E> delNode = pre.next;
    pre.next = delNode.next;
    delNode.next = null;
    return delNode.e;
}

public E removeFirst(){
    return remove();
}

public E removeLast(){
    return remove(size - );
}
           

5)toString方法

@Override
public String toString(){

    StringBuilder sb = new StringBuilder();
    sb.append("LinkedList[ ");
    Node<E> current = dummyHead.next;
    //sb.append("NULL -> ");
    while (current !=  null){
        sb.append(current.e+" -> ");
        current = current.next;
    }
    sb.append("NULL]");
    return sb.toString();
}
           

2. 雙向連結清單

1)頭部插入資料

//添加一個對前一個節點的引用
public Node previous;

 /**
   * 插入一個結點,在頭結點後進行插入
   */
  public void insertFirst(long value){
      Node node = new Node(value);
      if(first == null){
          last = node;
      }else{
          first.previous = node;
      }
      node.next = first;
      first = node;
  }
           

2)尾部插入資料

/**
   * 插入一個結點,從尾結點進行插入
   */
  public void insertLast(long value){
      Node node = new Node(value);
      if (first == null){
          first = node;
      }else{
          last.next = node;
          node.previous = last;
      }
      last = node;
  }
           

3)頭部删除資料

/**
   * 删除一個結點,在頭結點後進行删除
   */
  public Node deleteFirst(){
     if(first == null). return;
      Node current = first;
      if(first.next == null){
          last = null;
      }else{
          first.next.previous = null;
      }
      first = first.next;
      return current;
  }
           

4)尾部删除資料

/**
   * 删除尾節點 從尾部進行删除
   */
  public Node deleteLast(){
      Node current = last;
      if(first.next == null){
          first = null;
      }else{
          last.previous.next = null;
      }
      //後一個節點用後一個節點的前一個節點替換
      last = last.previous;
      return last;
  }
           

5)删除節點資料

/**
  * 根據資料删除節點
  * @param value
  * @return
  */
 public Node delete(long value){

     Node current = first;
     if(current == null){
         return null;
     }
     while (current.data != value){
         current = current.next;
         if(current == null){
             return null;
         }
     }
     if(current == first){
         first = first.next;
     }else{
         //目前節點的前一個節點的下一個節點就是保留目前節點的引用
         current.previous.next = current.next;
     }
     return current;
 }
           

3. 用連結清單實作棧

基于實作的單連結清單LinkedList
public class LinkedListStack<E> implements Stack<E>{

    private LinkedList<E> linkedList;
    public LinkedListStack(){
        linkedList = new LinkedList<>();
    }

    //入棧
    @Override
    public void push(E e) {
        linkedList.addFirst(e);
    }

    //出棧
    @Override
    public E pop() {
        return linkedList.removeFirst();
    }

    //擷取棧頂元素
    @Override
    public E peek() {
        return linkedList.getFirst();
    }

    @Override
    public boolean isEmpty() {
        return linkedList.isEmpty();
    }

    @Override
    public int size() {
        return linkedList.size();
    }

    @Override
    public String toString(){

        StringBuilder sb = new StringBuilder();
        sb.append("LinkedList[ ");
        Node<E> current = linkedList.getNode();
        while (current !=  null){
            sb.append(current.e+" -> ");
            current = current.next;
        }
        sb.append("NULL ]");
        return sb.toString();
    }
}
           

4. 用連結清單實作隊列

1)構造函數

//隊頭 隊尾
private Node<E> front;
private Node<E> tail;
private int size;
public LinkedListQueue(){
    front = null;
    tail = null;
    size = ;
}
           

2)入隊

@Override
public void enqueue(E e) {
    //4->3->2->1
    Node<E> node = new Node<>(e);
    if(tail == null){
        tail = node;
        front = tail;
    }else{
        tail.next = node;
        tail = tail.next;
    }
    size++;
}
           

3)出隊

@Override
public E dequeue() {
    //4->3->2->1
    if(isEmpty())
        throw new IllegalArgumentException("隊列是空的,不能出隊");
    Node<E> current = front;
    front = front.next;
    current.next = null;
    if(front == null)
        tail = null;
    size--;
    return current.e;
}
           

4)toString方法

@Override
public String toString(){

    StringBuilder sb = new StringBuilder();
    sb.append("LinkedList size "+ size +"\n");
    Node<E> current = front;
    sb.append("front[ ");
    while (current !=  null){
        sb.append(current.e+" -> ");
        current = current.next;
    }
    sb.append("NULL ] tail");
    return sb.toString();
}
           

5.聯系方式

QQ:1509815887