java实现链表相关操作

链表

1.实现单链表的基本操作

package com.DS;

class Node{
    Node next = null;
    int data ;
    public Node( int data){
        this.data = data;
    }
}

public class LinkedList {
    Node head = null;
    //在链表最后插入数据
    public void addNode(int data){
        Node newNode = new Node(data);
        if (head == null){
            head = newNode;
            return;
        }
        Node temp = head;
        while (temp.next!=null){
            temp = temp.next;
        }
        temp.next = newNode;
        return;
    }
    //删除第index个节点
    public void delete(int index){
        if(head == null){
            System.out.println("链表为空,无法进行删除操作");
            return;
        }
        if(index<1||index>length()){
            System.out.println("删除索引有误,无法进行删除操作");
            return;
        }
        //要删除的节点为头结点
        if (index == 1){
            head = head.next;
        }
        int i = 2;
        Node preNode = head;
        Node curNode = preNode.next;
        while (curNode != null){
            if (i == index){
                preNode.next = curNode.next;
                return;
            }
            preNode = curNode;
            curNode = curNode.next;
        }
    }
    //返回链表长度
    public int length(){
        int len = 0;
        Node temp = head;
        while (temp != null){
            len++;
            temp = temp.next;
        }
        return len;
    }
    //对链表进行排序,返回排序后的头结点
    public Node orderList(){
       Node nextNode = null;
       Node curNode = head;
       int temp;
       while (curNode.next!=null){
           nextNode = curNode.next;
           while (nextNode != null){
               if (curNode.data>nextNode.data){
                   temp = curNode.data;
                   curNode.data = nextNode.data;
                   nextNode.data = temp;
               }
               nextNode = nextNode.next;
           }
           curNode = curNode.next;
       }
       return head;
    }
    //打印链表
    public void printList(){
        Node node = head;
        while (node!=null){
            System.out.print(node.data+"——>");
            node = node.next;
        }
        System.out.println();
    }

    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.addNode(3);
        list.addNode(4);
        list.addNode(7);
        list.addNode(6);
        list.addNode(5);
        list.addNode(2);
        System.out.println("链表长度为"+list.length());
        System.out.println("原链表为:");
        list.printList();
        list.delete(2);
        System.out.println("删除操作后链表为");
        list.printList();
        System.out.println("排序后链表为");
        list.orderList();
        list.printList();
    }
}

2.从链表中删除重复数据

//方法1
   public void deleteduplecate(){
        Hashtable<Integer,Integer> table = new Hashtable<>();
        Node temp = head;
        Node pre = null;
        while(temp!=null){
            if(table.contains(temp.data)){
                pre.next = temp.next;
            }
            else {
                table.put(temp.data,1);
                pre = temp;
            }
            temp = temp.next;

        }
    }
    //方法2
    public void deleteduplecate(){
       Node p = head;
       while (p!=null){
           Node q = p;
           while (q.next!=null){
               if (q.next.data == p.data){
                   q.next = q.next.next;
               }
               else
                   q = q.next;
           }
           p = p.next;
       }
    }

3.找出单链表的倒数第k个元素

思路:查找过程中设置两个指针,让其中一个指针先走k-1步,当他的指针值为null时,另一个指针所指的位置就是倒数第k个元素。(java中没有指针,故采用引用)

 public Node findkElem(int k) {
        if (k < 1||k>length()) {
            return null;
        }
        Node p1 = head;
        Node p2 = head;
        for (int i = 0; i < k ; i++) {
            p1 = p1.next;
        }
        while (p1!=null){
            p1 = p1.next;
            p2 = p2.next;
        }
        return p2;
    }

4.实现链表反转

   public void ReverseList(){
        if (head == null||head.next==null){
            this.head= head;
        }
        Node preNode = null;
        Node curNode = head;
        Node nextNode ;
        while (curNode!=null){
            nextNode = curNode.next;
            curNode.next = preNode;
            preNode = curNode;
            curNode = nextNode;
        }
        this.head = preNode;
    }

5.从尾到头输出单链表

 public void printListReversely(Node head){
        if (head!=null){
            printListReversely(head.next);
            System.out.println(head.data);
        }
    }

6.寻找单链表的中间节点

思路:有两个指针同时从头开始遍历,一个快指针一次走两步,一个慢指针一次走一步,当快指针走到链表尾部时,慢指针刚好到达链表中部(当链表长度为奇数时,慢指针刚好到达链表中间位置;当链表长度为偶数时,慢指针指向的节点以及下一个节点都是链表的中间节点)

public Node searchMid(Node head){
        Node fast = this.head;
        Node slow = this.head;
        while(fast!=null && fast.next!=null && fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

7.判断一个链表是否带环

思路:定义两个指针fast和slow,其中fast每次前进两步,slow每次前进一步,每移动一次两个都要进行比较,直到当快指针等于慢指针时,就证明这个链表是带环的单向链表;当fast先走到尾部为null值时就证明为无环链表。

    public boolean isLoop(Node head){
        Node fast = head;
        Node slow = head;
        while (fast!=null&&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if (fast==slow){
                return true;
            }
        }
        return  !(fast==null||fast.next==null);
    }

8.在不知道头指针的情况下删除指定节点

分为两种情况来讨论:
1.若待删除的节点为链表尾节点,则无法删除,因为删除后无法使其前驱结点的next指向null;
2.若待删除的节点不是尾节点,则可以通过交换这个节点与后继节点的值,然后删除后继节点。

public boolean deleteNode(Node n){
        if (n==null||n.next==null){
            return false;
        }
        int temp = n.data;
        n.data=n.next.data;
        n.next.data=temp;
        n.next = n.next.next;
        return true;    
    }

9.如何判断两个链表相交

思路:如果两个链表相交,那么它们一定有着相同的尾节点,分别遍历两个链表,记录它们的尾节点,如果它们的尾节点相同,那么这两个链表相交,否则不相交。

    public boolean isIntersect(Node h1,Node h2){
        if (h1==null||h2==null){
            return false;
        }
        Node tail1=h1;
        Node tail2=h2;
        while (tail1.next!=null){
            tail1 = tail1.next;
        }
        while (tail2.next!=null){
            tail2 = tail2.next;
        }
        return tail1==tail2;
    }

引申:如果两个链表相交,如何找到它们相交的第一个节点?
首先分别计算两个链表的长度len1和len2(假设len1>len2),接着先对链表1遍历(len1-len2)个节点到节点p,此时节点p与链表2的head到相交点距离相同,此时同时遍历两条链表,直到遇到相同的节点为止,此节点就是他们相交的第一个节点。
在这里插入图片描述

    public static Node getFirstMeetNode(Node head1,Node head2){
        if (head1==null||head2==null){
            return null;
        }
        Node tail1 = head1;
        Node tail2 = head2;
        int len1 = 1;
        int len2 = 1;
        while (tail1.next!=null){
            tail1 = tail1.next;
            len1++;
        }
        while (tail2.next!=null){
            tail2 = tail2.next;
            len2++;
        }
        //两链表不相交
        if (tail1!=tail2){
            return null;
        }
        Node h1=head1;
        Node h2=head2;
        if (len1>len2){
            int d=len1-len2;
            while (d!=0){
               h1 = h1.next;
               d--;
            }
        }else{
            int d = len2-len1;
            while (d!=0){
                h2=h2.next;
                d--;
            }
        }
        while (h1!=h2){
            h1=h1.next;
            h2=h2.next;
        }
        return h1;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值