面试常问——链表

链表的增、删、排序

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

public class C1 {
    //头结点
    Node head=null;

    public static void main(String[] args) {
        C1 linkList = new C1();
        linkList.addNode(3);
        linkList.addNode(2);
        linkList.addNode(1);
        linkList.printLink(linkList.head);
        System.out.println("len:"+linkList.size(linkList.head));
        linkList.delete(2);
        linkList.printLink(linkList.head);
        System.out.println("len:"+linkList.size(linkList.head));
        Node head = linkList.orderList();
        linkList.printLink(head);
    }

    /**
     * 插入节点
     */
    private  void addNode(int data) {
        Node node = new Node(data);
        if (head==null){
            head=node;
            return;
        }
        Node p=head;
        while (p.next!=null){
            p=p.next;
        }
        p.next=node;
    }

    /**
     * 给定头结点计算链表长度
     * @param head
     * @return
     */
    private  int size(Node head){
        int size=0;
        Node p=head;
        while (p!=null){
            size++;
            p=p.next;
        }
        return size;
    }

    /**
     * 打印链表
     * @param head
     */
    private  void printLink(Node head){
        Node p=head;
        while (p!=null){
            System.out.println(p.data);
            p=p.next;
        }
    }

    /**
     * 删除第index个节点
     * @param index
     * @return
     */
    private boolean delete(int index){
        if (index<1||index>size(head)){
            return false;
        }
        if (index==1){
            head=head.next;
            return true;
        }
        int i=2;
        Node preNode=head;
        Node curNode=preNode.next;
        while (curNode!=null){
            if (i==index){
                preNode.next=curNode.next;
                return true;
            }
            preNode=curNode;
            curNode=curNode.next;
            i++;
        }
        return true;
    }

    /**
     * 对链表进行排序
     */
    private Node orderList(){
        Node nextNode=null;
        int tmp=0;
        Node curNode=head;
        while (curNode.next!=null){
            nextNode=curNode.next;
            while (nextNode!=null){
                if (curNode.data>nextNode.data){
                    tmp=curNode.data;
                    curNode.data=nextNode.data;
                    nextNode.data=tmp;
                }
                nextNode=nextNode.next;
            }
            curNode=curNode.next;
        }
        return head;

    }
}

如何删除链表中重复的数据

1、使用hashtable,遍历链表,如果hashtable中不存在该节点,就将该节点添加到hashtable中,如果存在则删除该节点;

 private void deleteDuplecate(Node head){
        Hashtable<Integer, Integer> table = new Hashtable<>();
        Node pre=null;
        Node tmp=head;
        while (tmp!=null){
            if (table.containsKey(tmp.data)){
                pre.next=tmp.next;
            }else {
                table.put(tmp.data,1);
                pre=tmp;
            }
            tmp=tmp.next;
        }

    }

2、使用双重循环,挨个查找链表中是否有该元素的重复值;

private void deleteDuplecate1(Node head){
        Node outerP=head;
        while (outerP!=null){
            Node innerP=outerP;
            while (innerP.next!=null){
                if (outerP.data==innerP.next.data){
                    innerP.next=innerP.next.next;
                }else {
                    innerP=innerP.next;
                }
            }
            outerP=outerP.next;
        }
    }

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

  1. 先从头遍历一遍计算出链表的长度,然后从头遍历删除第n-k个节点,需要遍历两遍 时间复杂度O(n);
  2. 从头开始检测距离每个节点k的位置是否为空,如果为空说明当前节点是倒数第k个 时间复杂度O(kn);
  3. 设置两个指针,第二个指针距离第一个指针k,然后两指针往后移动,直到第二个指针为空 时间复杂度O(n-k);
 private Node findElem(int k,Node head){
        Node preNode=head;
        Node afterNode=preNode;
        int t=0;
        while (t<k-1&&afterNode!=null){
            afterNode=afterNode.next;
            t++;
        }
        if(afterNode==null){
            System.out.println("k 不合法");
            return null;
        }

        while (afterNode.next!=null){
            preNode=preNode.next;
            afterNode=afterNode.next;
        }
        return preNode;
    }

链表反转

面试常问——链表_第1张图片

private Node reverse(Node head){
        Node reHead=null;
        Node cur=head;
        Node pre=null;
        while (cur!=null){
            Node tmp=cur.next;

            cur.next=pre;
            if (tmp==null){
                reHead=cur;
            }
            pre=cur;
            cur=tmp;
        }
        return reHead;

    }

如何从尾到头输出单链表

 private void printListReversely(Node pListHead){
        if (pListHead!=null){
            printLink(pListHead.next);
            System.out.println(pListHead.data);
        }
    }

寻找链表的中间节点

  1. 遍历链表计算链表的长度len,然后找到第len/2个节点,需要遍历两次;
  2. 指定一个慢指针一次走一步,一个快指针一次走两步,当快指针到达链表尾部的时候,如果链表长度时奇数,则慢指针指向中点,如果是偶数慢指针指向的节点和它的下一个节点都是中点。
private boolean IsLoop(Node head){
        Node slow=head;
        Node fast=head;
        if (fast==null){
            return false;
        }
        while (fast!=null&&fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if (fast==slow){
                return true;
            }
        }
        return false;
    }

如何寻找入口节点:先找到两个指针相遇的地方,快指针指向这个地方,然后再将慢指针指向链表头,再每次两个指针都移动一次,两个指针相遇的地方就是环入口。

如何在不知道头指针的情况下删除指定结点

如果删除的结点是尾节点,则无法删除;如果删除不是尾节点,则先将它与它的下一个节点值交换,然后删除它的下一个节点;

private boolean deleteNode(Node node){
        if (node==null||node.next==null){
            return false;
        }
        int tmp=node.data;
        node.data=node.next.data;
        node.next.data=tmp;
        node.next=node.next.next;
        return true;
    }

如何判断两个链表是否相交

如何两个链表相交,则它们肯定是同一个尾节点,遍历两个链表,判断它们的尾结点是否相同;

private boolean isIntersect(Node n1,Node n2){
        if (n1==null|n2==null){
            return false;
        }
        Node h1=n1;
        while (h1.next!=null)
            h1=h1.next;
        Node h2=n2;
        while (h2.next!=null)
            h2=h2.next;
        
        return h1==h2;
    }

如何找到相交的节点:先判断两个两个链表是否有有交点,顺便计算每个链表的长度,如果len1-len2大于0,则先将指针指向第一个链表的len1-len2处,这时两个指针距离交点的距离相等,然后再移动两个指针,直到指向同一个节点。

private Node isIntersect(Node n1,Node n2){
        if (n1==null|n2==null){
            return null;
        }
        Node h1=n1;
        int len1=1;
        while (h1.next!=null) {
            h1 = h1.next;
            len1++;
        }
        Node h2=n2;
        int len2=1;
        while (h2.next!=null) {
            h2 = h2.next;
            len2++;
        }

        if (h1!=h2){
            return null;
        }
        Node t1=n1;
        Node t2=n2;
        if (len1>len2){
            int d=len1-len1;
            while (d!=0){
                t1=t1.next;
                d--;
            }
        }else {
            int d=len2-len1;
            while (d!=0){
                t2=t2.next;
                d--;
            }
        }
        while (t1!=t2){
            t1=t1.next;
            t2=t2.next;
        }
        return t1;
    }

你可能感兴趣的:(Java语言,数据结构,面试总结)