Java 單鏈表數據結構相關算法代碼

單鏈表相關算法的java代碼 ,歡迎提出意見和建議!


public class ListNode {
    private ListNode(int value){
      this.value=value;
    }
    private int value;      // 鏈表節點值
    private ListNode next ; // 下一個節點


  public static void main(String[] args) {
    ListNode node1 = new ListNode(1);
    ListNode node2 = new ListNode(2);
    ListNode node3 = new ListNode(3);
    ListNode node4 = new ListNode(4);
    ListNode node5 = new ListNode(5);
    ListNode node6 = new ListNode(109);

    System.out.println("**************構造鏈表***************");
    node1.next=node2;
    node2.next=node3;
    node3.next=node4;
    node4.next=node5;
    node5.next=node6;
    System.out.println("**************原始鏈表***************");
    printList(node1);
    System.out.println("**************反轉鏈表***************");
    ListNode head = reverseList(node1);
    printList(head);
    System.out.println("**************複製鏈表***************");
    ListNode copyList = copyList(node1);
    printList(copyList);
    System.out.println("**************原始鏈表***************");
    printList(node1);
    System.out.println("**************合併鏈表***************");
    ListNode mergeList =  mergeList(node1,copyList);
    printList(mergeList);
    System.out.println("**************是否相交***************");
    System.out.println(isIntersect(node1,node4));
    System.out.println("**************是否有環***************");
//    node1.next.next.next=node3;   // 模擬環
    System.out.println(existsCycle(node6));
    System.out.println(existsCycle(node1));
    System.out.println("**************環入口節點值***************");
    ListNode enter = enterNode(node1);
    System.out.println(enter == null?null:enter.value);

    System.out.println("**************插入有序***************");
    ListNode orderHead = insertNode(node1,6);
    printList(orderHead);

    System.out.println("**************倒數K節點***************");
    ListNode lastkNode = findLastKNode(node1,7);
    System.out.println(lastkNode== null?null:lastkNode.value);

  }

  /**
   * 打印單鏈表
   * @param head 頭節點
   */
  private static void printList(ListNode head){
      while(head != null){
        System.out.println(head.value);
        head = head.next;
      }
    }


  /**
   * 反轉鏈表
   * @param head 原頭節點
   * @return 新頭節點
   */
    private static ListNode reverseList(ListNode head){
        if(head == null ) return null;
        ListNode newList = new ListNode(head.value); // 新鏈表頭節點
        while( head.next != null ){
            ListNode temp = new ListNode(head.next.value);  // 不能直接用裏面的節點,否則出現死循環
            temp.next = newList;
            newList = temp;
            head = head.next;
        }
        return newList;
    }

  /**
   * 複製單鏈表(爲了判斷沒幹擾到原來的鏈表,加100進行測試)
   * @param head 原來鏈表頭節點
   * @return 新鏈表頭節點
   */
  private static ListNode copyList(ListNode head){
      if(head == null) return null;
      ListNode newHead = new ListNode(head.value+100);
      ListNode newHead1 = newHead ; // 新鏈表的頭節點
      while (head.next != null ){
        ListNode temp = new ListNode(head.next.value+100);
        newHead.next = temp;
        newHead = newHead.next;
        head = head.next;
      }
      return newHead1;
  }

  /**
   * 合併兩個有序鏈表
   * @param n1 第一個鏈表節點
   * @param n2 第二個鏈表節點
   * @return 新鏈表頭節點
   */
  private static ListNode mergeList(ListNode n1,ListNode n2){
      if( n1 == null ) return n2;
      if( n2 == null ) return n1;
      ListNode head = null;
      ListNode head1 = head;
      while(n1 != null && n2 != null) {
        ListNode node = null;
        if (n1.value <= n2.value) {
          node = new ListNode(n1.value);
          n1 = n1.next;
        } else {
          node = new ListNode(n2.value);
          n2 = n2.next;
        }
        if (head == null) {
          head = node;
          head1 = head;
        }
        else {
          head.next=node;
          head = head.next;
        }
      }
      if (n1 != null ){   // 把剩餘的鏈表接上去
        head.next= n1;
      }
      if (n2 != null ){   // 把剩餘的鏈表接上去
        head.next = n2;
      }
      return head1;
  }

  /**
   * 判斷兩個鏈表是否相交
   * @param n1 鏈表1
   * @param n2 鏈表2
   * @return 相交返回true 否則返回false
   */
  private static boolean isIntersect(ListNode n1,ListNode n2){
      if(n1 == null || n2 == null){
        return true;
      }
      int len1 = 0;
      int len2 = 0;

      ListNode nn1 = n1;
      ListNode nn2 = n2;

      // 計算鏈表長度
      while (nn1 != null){
        len1 ++;
        nn1 = nn1.next;
      }
      // 計算鏈表長度
      while (nn2 != null){
        len2 ++;
        nn2 = nn2.next;
      }

      // 先讓鏈表往前走一段 剩餘相同的長度 開始遍歷
      if( len1 >= len2 ){
        int count = len1-len2;
        for (int i = 0; i < count ; i++) {
            n1 = n1.next;
        }
      }
      else {
        int count = len2-len1;
        for (int i = 0; i < count ; i++) {
          n2 = n2.next;
        }
      }
      while (n1 != null){
        if(n1 == n2){
          return true;
        }
        else {
          n1=n1.next;
          n2=n2.next;
        }
      }
      return false;
  }

  /**
   * 是否存在環
   * @param head 頭節點
   * @return 存在返回true 否則返回false
   */
  private static boolean existsCycle(ListNode head){
    if( head == null ) return false;
    ListNode slow = head;
    ListNode fast = head;
    // 快慢指針 快指針一下子走兩步 慢指針一次一步
    while ((slow = slow.next) != null && (fast = fast.next.next) != null){
        if(slow == fast){
          return true;
        }
    }
    return false;
  }

  /**
   * 環入口節點
   * @param head 頭節點
   * @return 存在返回true 否則返回false
   */
  private static ListNode enterNode(ListNode head){
    if( head == null ) return null;
    ListNode slow = head;
    ListNode fast = head;

    // 快慢指針往前走 如果快指針的下個節點爲空了 證明沒環
    // 設 頭節點到環入口的長度爲 y 相遇點距離 入口爲 x 環長度爲 r 快指針走了n圈
    // 則 快指針走過的路程是慢指針的兩倍  2(x+y)=nr+x+y
    // 化簡  y=nr=x
    // 繼續  y=(n-1)r+(r-x)    r-x 爲 相遇點到環入口點的長度
    // 這時候 快指針從頭開始走 慢指針也開始一步步走 必會相遇
    // y - (r-x) = (n-1)r
    while ((slow = slow.next) != null && (fast = fast.next.next) != null){
      if(slow == fast){
        fast = head;
        break;
      }
    }
    // 不存在環的時候報錯問題
    if(fast != null ){
      // 快指針回到頭部  開始每次走一步
      while ((slow = slow.next) != null && (fast = fast.next) != null){
        if(slow == fast){
          return slow;
        }
      }
    }
    return null;
  }


  /**
   * 有序單向循環鏈表插入結點
   * @param head 有序鏈表頭節點
   * @param number 插入的值
   */
  private static ListNode insertNode(ListNode head,int number){
    // 當空鏈表 或者插入的值比第一個小的時候
    if( head == null || number <= head.value) {
      ListNode newHead = new ListNode(number);
      if(head != null){
        newHead.next=head;
      }
      return newHead;
    }
    // 其他情況還返回老的鏈表的頭節點
    ListNode oldHead = head;
    while (head != null){
      int temp = head.value;
      if(temp <= number){
        if(head.next != null) {   // 是否走到頭了
          if(head.next.value >= number){ // 找到插入位置了
            ListNode tmpNode = new ListNode(number);
            tmpNode.next = head.next;
            head.next= tmpNode;
            return oldHead;
          }
        }
        else {    // 鏈表尾部了
          ListNode tmpNode = new ListNode(number);
          head.next = tmpNode;
        }
      }
      // 繼續向後查找
      head = head.next;
    }
    return oldHead;
  }

  /**
   * 查找鏈表的倒數第K個節點
   * @param head 頭節點
   * @param pos  位置
   * @return 倒數位置
   */
  public static ListNode findLastKNode(ListNode head,int pos){
      if(head == null || pos < 0){
        return null;
      }
      else {
        int i = 0;  // 位置初始化爲 1
        ListNode result = head;
        while (head != null ){
          // 讓快指針先走 n 步
          if(i >= pos){
            result = result.next;
          }
          head = head.next;
          i++;
        }
        // 判斷是否超過鏈表長度
        if(i < pos){
          return null;
        }
        return result;
      }
  }


}

輸出

**************原始鏈表***************
1
2
3
4
5
109
**************反轉鏈表***************
109
5
4
3
2
1
**************複製鏈表***************
101
102
103
104
105
209
**************原始鏈表***************
1
2
3
4
5
109
**************合併鏈表***************
1
2
3
4
5
101
102
103
104
105
109
209
**************是否相交***************
true
**************是否有環***************
false
false
**************環入口值***************
null
**************插入有序***************
1
2
3
4
5
6
109
**************倒數K節點***************
1

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章