[JAVA]模擬雙向鏈接串列(DoublyLinkedList)

模擬雙向鏈接串列(DoublyLinkedList)的新刪修查

import java.util.Stack;

public class Test {

  public static void main(String[] args) {

    DoublyLinkedList doublyLinkedList = new DoublyLinkedList();
    HeroNode heroNode1 = new HeroNode(1, "道明寺 司", "道明寺");
    HeroNode heroNode2 = new HeroNode(2, "花澤 類", "花澤類");
    HeroNode heroNode3 = new HeroNode(3, "西門 總二郎", "西門");
    HeroNode heroNode4 = new HeroNode(4, "美作 玲", "美作");
//    doublyLinkedList.add(heroNode2);
//    doublyLinkedList.add(heroNode3);
//    doublyLinkedList.add(heroNode1);
//    doublyLinkedList.add(heroNode4);
//    doublyLinkedList.showAllNodes();

    doublyLinkedList.addByOrder(heroNode2);
    doublyLinkedList.addByOrder(heroNode3);
    doublyLinkedList.addByOrder(heroNode1);
    doublyLinkedList.addByOrder(heroNode4);
    doublyLinkedList.showAllNodes();

    heroNode2 = new HeroNode(5, "花澤 類~~", "花澤類~~");
    doublyLinkedList.update(heroNode2);
    System.out.println("修改後的LinkedList:");
    doublyLinkedList.showAllNodes();

//    doublyLinkedList.delete(1);
//    doublyLinkedList.delete(4);
//    doublyLinkedList.delete(2);
//    doublyLinkedList.delete(3);
//    doublyLinkedList.delete(5);
//    System.out.println("刪除後的LinkedList:");
//    doublyLinkedList.showAllNodes();
//
//    int effectiveCount = doublyLinkedList.getEffectiveCount(doublyLinkedList.getHead());
//    System.out.println("有效節點數 = " + effectiveCount);
//
//    HeroNode lastedNode = doublyLinkedList.getLastedNode(doublyLinkedList.getHead(), 4);
//    System.out.println("倒數第4個節點 = " + lastedNode);
//
//    // 反轉雙向鏈接串列
//    System.out.println("顯示反轉雙向鏈接串列:");
//    doublyLinkedList.reverseLinkedList(doublyLinkedList.getHead());
//    doublyLinkedList.showAllNodes();
//    System.out.println("打印使用資料結構Stack儲存的逆序LinkedList!");
//    reversePrint(doublyLinkedList.getHead());
  }
}

/**
 * 新建類別(DoublyLinkedList)模擬雙向鏈接串列
 */
class DoublyLinkedList {

  // step1:new a head node, without data
  private HeroNode head = new HeroNode(0, "", "");

  public HeroNode getHead() {
    return head;
  }

  // step2:aim to add new node from the end of LinkedList
  // so create a function add()

  /**
   * 從雙向鏈表最後新增節點
   * @param heroNode
   */
  public void add(HeroNode heroNode) {
    // connect a node from the end, but not to change head node
    HeroNode temp = head;
    while (true) {
      if (temp.getNextNode() == null) {
        // already found the end of node, can jump out loop to connect a node
        break;
      }
     temp = temp.getNextNode();
    }
    // (temp.next == null) be true, so add a new node here
    temp.setNextNode(heroNode);
    heroNode.setPreNode(temp);
  }

  /**
   * 模擬雙向鏈接串列按照英雄編號順序新增
   * @param heroNode 頭節點
   */
  public void addByOrder(HeroNode heroNode) {
    HeroNode temp = head;
    while (true) {
      if (temp.getNextNode() == null || temp.getNextNode().getHeroNo() > heroNode.getHeroNo()) { // headNo:1 heroNode:2 headNextNode:4(temp.getNextNode)
        // exchange position between three nodes
        HeroNode next = temp.getNextNode();
        temp.setNextNode(heroNode);
        temp.getNextNode().setNextNode(next);
        break;
      } else if (temp.getNextNode().getHeroNo() == heroNode.getHeroNo()) {
        System.out.printf("此英雄編號:%d已存在,無法新增此節點\n", heroNode.getHeroNo());
        break;
      }
      temp = temp.getNextNode();
    }
  }

  public void update(HeroNode heroNode) {
    // step1:the node next to head is null, cannot update then return function
    if (head.getNextNode() == null) {
      System.out.println("鏈接串列為空,無法更新~");
      return;
    }
    HeroNode temp = head.getNextNode();
    while (true) {
      if (temp.getNextNode() == null) {
        // already moved at the end of LinkedList
        System.out.printf("鏈接串列已走到最後,找不到該英雄編號: %d\n", heroNode.getHeroNo());
        return;
      } else if (temp.getHeroNo() == heroNode.getHeroNo()) {
        // heroNo is like primary key to find particular HeroNode
        temp.setHeroName(heroNode.getHeroName());
        temp.setHeroNickname(heroNode.getHeroNickname());
        break;
      }
      temp = temp.getNextNode();
    }
  }

  public void delete(int heroNo) {
    if (head.getNextNode() == null) {
      System.out.println("鏈接串列為空,無法刪除");
      return;
    }
    HeroNode temp = head.getNextNode();
    while (true) {
      if (temp == null) {
        System.out.printf("鏈接串列已走到最後,找不到該英雄編號:%d\n", heroNo);
        return;
      } else if (temp.getHeroNo() == heroNo) {
        // just delete current node(temp) directly
        temp.getPreNode().setNextNode(temp.getNextNode());
        // if delete the end of node, can't run: temp.getNextNode(), otherwise throws NullPointerException
        if (temp.getNextNode() != null) {
          temp.getNextNode().setPreNode(temp.getPreNode());
        }
        break;
      }
      temp = temp.getNextNode();
    }
  }


  // step3:show LinkedList all nodes
  // so create a function showList()
  public void showAllNodes() {
    // to check this LinkedList has node or not? but not to change head node
    HeroNode temp = head.getNextNode();
    while (true) {
      if (temp == null) {
        // already moved to the end of LinkedList then return function
        return;
      }
      System.out.println(temp);
      temp = temp.getNextNode();
    }
  }

  /**
   * 取得鏈接串列的有效節點數
   * @param head 頭節點
   * @return count 有效節點數(排除頭節點)
   */
  public int getEffectiveCount(HeroNode head) {
    int count = 0;
    // the node next to headNode is not null then loop, otherwise return!
    if (head.getNextNode() == null) {
      return 0;
    }
    // use current node to store copied node
    HeroNode current = head.getNextNode();
    while (true) {
      if (current == null) {
        return count;
      }
      count++;
      current = current.getNextNode();
    }
  }


  /**
   *
   * @param head 頭節點
   * @param inLastOrder 倒數第?個
   * @return 倒數第?個節點
   */
  public HeroNode getLastedNode(HeroNode head, int inLastOrder) {
    // head.next == null,代表鏈接串列為空
    if (head.getNextNode() == null) {
      return null;
    }
    // verify valid inLastOrder
    // length = effectiveCount
    // newLength
    int newLength = getEffectiveCount(head) - inLastOrder;
    if (newLength > getEffectiveCount(head) && newLength < 0) {
      return null;
    }

    // create a temp node to store node
    HeroNode temp = head.getNextNode();
    for (int i = 0; i < newLength; i++) {
      temp = temp.getNextNode();
    }
    return temp;
  }

  /**
   * 取得反轉的雙向鏈接串列
   * @param head 原鏈接串列頭節點
   */
  public void reverseLinkedList(HeroNode head) {

    //origin linkedList's node less then two, just return
    if (head.getNextNode() == null || head.getNextNode().getNextNode() == null) {
      return;
    }
    HeroNode cur = head.getNextNode();
    HeroNode next = null;
    // create a new LinkedList
    HeroNode reverseHead = new HeroNode(0, "", "");
    while (cur != null) {
      // store it for cur node next time to move on
      next = cur.getNextNode();
      // the node next to cur point to reverseHead.next
      cur.setNextNode(reverseHead.getNextNode());
      // let cur node to replace reverseHead.next
      reverseHead.setNextNode(cur);
      // cur node just move on
      cur = next;
    }
    // head node point to reverseHead.next
    head.setNextNode(reverseHead.getNextNode());
  }

  /**
   * 逆序打印雙向鏈接串列
   * 使用資料結構Stack後進先出 特性
   * @param head 頭節點
   */
  public static void reversePrint(HeroNode head) {
    if (head.getNextNode() == null) {
      return;
    }
    HeroNode cur = head.getNextNode();
    Stack<HeroNode> heroStack = new Stack<>();
    while (cur != null) {
      // add current node to Stack
      heroStack.push(cur);
      cur = cur.getNextNode();
    }
    while (heroStack.size() > 0) {
      // loop heroStack to print all heroNode
      System.out.println(heroStack.pop());
    }
  }
}



/**
 * 新建類別(HeroNode)模擬LinkedList的節點
 */
class HeroNode {

  private int heroNo;
  private String heroName;
  private String heroNickname;
  private HeroNode nextNode;
  private HeroNode preNode;

  // constructor
  public HeroNode(int no, String name, String nickname) {
    this.heroNo = no;
    this.heroName = name;
    this.heroNickname = nickname;
  }

  public int getHeroNo() {
    return heroNo;
  }

  public HeroNode getNextNode() {
    return nextNode;
  }

  public void setNextNode(HeroNode nextNode) {
    this.nextNode = nextNode;
  }

  public HeroNode getPreNode() {
    return preNode;
  }

  public void setPreNode(HeroNode preNode) {
    this.preNode = preNode;
  }

  public String getHeroName() {
    return heroName;
  }

  public String getHeroNickname() {
    return heroNickname;
  }

  public void setHeroName(String heroName) {
    this.heroName = heroName;
  }

  public void setHeroNickname(String heroNickname) {
    this.heroNickname = heroNickname;
  }

  @Override
  public String toString() {
    final StringBuilder sb = new StringBuilder("HeroNode{");
    sb.append("heroNo=").append(heroNo);
    sb.append(", heroName='").append(heroName).append('\'');
    sb.append(", heroNickname='").append(heroNickname).append('\'');
    sb.append('}');
    return sb.toString();
  }
}

如有敘述錯誤,還請不吝嗇留言指教,thanks!