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

 

程序 = 数据结构 + 算法  程序是为了解决实际问题而存在的。然而为了解决问题,必定会使用到某些数据结构以及设计一个解决这种数据结构算法。如果说各种编程语言是程序员的招式,那么数据结构算法就相当于程序员的内功。编程实战算法,不是念PPT,我们讲的就是实战与代码实现与企业应用。程序 = 数据结构 + 算法                ——图灵奖得主,计算机科学家N.Wirth(沃斯)作为程序员,我们做机器学习也好,做python开发也好,java开发也好。有一种对所有程序员无一例外的刚需 —— 算法数据结构日常增删改查 + 粘贴复制 + 搜索引擎可以实现很多东西。同样,这样也是没有任何竞争力的。我们只可以粘贴复制相似度极高的功能,稍复杂的逻辑没有任何办法。语言有很多,开发框架更是日新月异3个月不学就落后我们可以学习很多语言,很多框架,但招聘不会考你用5种语言10种框架实现同一个功能。真正让程序员有区分度,企业招聘万年不变的重点 —— 算法数据结构算法代表程序员水平的珠穆朗玛。如果说各种编程语言是程序员的招式,那么数据结构算法就相当于程序员的内功。 想写出精炼、优秀的代码,不通过不断的锤炼,是很难做到的。 开这个系列的目的是为了自我不断积累。不积跬步无以至千里嘛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值