Java——关于链表的一些简单操作

public class Node {
    
    
    int data;
    Node next = null;

    Node(int data) {
    
    
        this.data = data;
    }
}
import java.util.Hashtable;

public class MyLinkedList {
    
    

    // 链表头的引用
    Node head = null;

    /**
     * 在链表中加入数据,加入到链表尾
     * 
     * @param data 元素的数据
     */
    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;
    }

    /**
     * 删除第index个位置的元素。
     * 
     * @howtodo 首先判断index是否超出范围。
     *          在判断index是否是指第一个元素。如果不是,则进行下面的做法。遍历到第index个元素,使得其前一个元素指向index+1个元素。
     * @param index
     * @return
     */
    public Boolean deleteNode(int index) {
    
    
        if (index < 1 || index > this.length()) {
    
    
            return false;
        }

        if (index == 1) {
    
    
            head = head.next;
            return true;
        }
        int i = 2;

        Node preNode = head;
        Node curNode = head.next;

        while (curNode != null) {
    
    
            if (i == index) {
    
    
                preNode.next = curNode.next;
                return true;
            }

            preNode = curNode;
            curNode = curNode.next;
            i++;
        }

        return true;
    }

    /**
     * 返回链表的长度
     * 
     * @return
     */
    public int length() {
    
    
        int length = 0;
        Node temp = head;
        while (temp != null) {
    
    
            length++;
            temp = temp.next;
        }
        return length;
    }

    /**
     * 对链表进行排序
     * 
     * @howtodo 使用双层循环,求出第i个元素后面的元素的最小值,并进行相应交换。
     */
    public Node sortList() {
    
    
        Node nextNode = null;
        int temp = 0;
        Node curNode = head;

        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;
    }

    /**
     * 删除链表中的重复数据
     * 
     * @howtodo 创建一个hash表用于记录之前没有出现过的元素。再遍历链表,如果遇到之前出现过的元素,则使其上一个元素指向其直接后继元素。
     */
    public void deleteDuplecate() {
    
    
        Hashtable<Integer, Integer> table = new Hashtable<>();
        Node temp = head;
        Node pre = null;

        while (temp != null) {
    
    
            if (table.containsKey(temp.data)) {
    
    
                pre.next = temp.next;
            } else {
    
    
                table.put(temp.data, 1);
                pre = temp;
            }
            temp = temp.next;
        }
    }

    /**
     * 删除链表中的方法2
     * 
     * @howtodo 使用双层循环遍历链表,判断当前元素后面的元素是否有重复的,如果有,则删除。
     */
    public void deleteDuplecate2() {
    
    
        Node p = head;
        while (p != null) {
    
    
            Node q = p;
            while (q.next != null) {
    
    
                if (p.data == q.next.data) {
    
    
                    q.next = q.next.next;
                } else {
    
    
                    q = q.next;
                }
            }
            p = p.next;
        }
    }

    /**
     * 一次遍历找到链表中的第k个元素 注意:需要处理k的无效取值
     * 
     * @howtodo 设置两个指针p1,p2。初始位置它们都指向头节点。后面,对p1进行k-1个位置的移动,
     *          接着在对p1,p2进行移动,知道p1到达最后一个节点。此时,p2指向的就是第倒数第k个节点。
     * 
     * @thinking 用两个指针可以固定两个指针间的距离,用于解体。
     * 
     * @param k 位置k
     */
    public Node findElement(int k) {
    
    
        if (k < 1)
            return null;
        Node p1 = head;
        Node p2 = head;

        for (int i = 0; i < k - 1 && p1 != null; i++)
            p1 = p1.next;

        if (p1 == null) {
    
    
            System.out.println("k超出链表长度");
            return null;
        }

        // 判断p1是否到最后一个节点
        while (p1.next != null) {
    
    
            p1 = p1.next;
            p2 = p2.next;
        }
        return p2;
    }

    /**
     * 反转链表
     * 
     * @howtodo 用三个指针分别指向前一个节点,当前节点,下一个结点,然后遍历链表。每一次遍历对当前访问过的节点进行反转。
     */
    public void reverse() {
    
    
        // 用与保存反转后的链表的头节点
        Node pReversedHead = head;
        // 用于遍历链表
        Node pNode = head;
        Node pPrev = null;

        while (pNode != null) {
    
    
            Node pNext = pNode.next;
            // 当到最后一个结点时,记录下来。
            if (pNext == null) {
    
    
                pReversedHead = pNode;
            }
            pNode.next = pPrev;
            pPrev = pNode;
            pNode = pNext;
        }
        this.head = pReversedHead;
    }

    /**
     * 从尾到头输出链表中的元素
     * 
     * @howtodo 创建一个栈,然后遍历链表,把元素放进去。最后输出栈里的元素。
     */
    public void printListReversely(Node node) {
    
    
        if (node != null) {
    
    
            printListReversely(node.next);
            System.out.println(node.data + " ");
        }
    }

    /**
     * 寻找单链表的中间结点
     * 
     * @howtodo 创建一个快指针和慢指针,遍历链表,快指针走两步,慢指针走一步。当快指针到最后不能走时,此时慢指针指到的一定是中点
     * @return
     */
    public Node searchMid() {
    
    
        // 快指针
        Node p1 = head;
        // 慢指针
        Node p2 = head;
        while (p1 != null && p1.next != null && p1.next.next != null) {
    
    
            p1 = p1.next.next;
            p2 = p2.next;
        }
        return p2;
    }

    /**
     * 判断链表是否有环
     * 
     * @howtodo 创建一个快指针和慢指针,遍历链表,快指针走两步,慢指针走一步。如果快指针最后为null,则无环,如果它们相遇,则有环。
     * @return
     */
    public boolean isLoop() {
    
    
        Node fast = head;
        Node slow = 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 !(fast == null || fast.next == null);
    }

    /**
     * 找到环的入口点
     * 
     * @howtodo 链表头与相遇点遍历的第一个相遇点。
     * @return
     */
    public Node findLoopPort() {
    
    
        Node slow = head;
        Node fast = head;

        // 找到相遇点
        while (fast != null && fast.next != null) {
    
    
            slow = slow.next;
            fast = fast.next.next;

            if (slow == fast)
                break;
        }

        if (fast == null || fast.next == null) {
    
    
            return null;
        }
        slow = head;
        while (slow != fast) {
    
    
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }

    /**
     * 在不知道头指针的情况下删除指定结点
     * 
     * @howtodo 把当前节点的值变成直接后继节点的值,并删除直接后继节点。
     * @param n 要删除的节点
     * @return
     */
    public boolean deleteNode2(Node n) {
    
    
        if (n == null || n.next == null) {
    
    
            return false;
        }

        int temp = n.next.data;
        n.next = n.next.next;
        n.data = temp;
        return true;
    }

    @Override
    public String toString() {
    
    
        Node temp = head;
        StringBuilder sBuilder = new StringBuilder();
        sBuilder.append("[");
        while (temp != null) {
    
    
            sBuilder.append(temp.data);
            temp = temp.next;

            if (temp != null) {
    
    
                sBuilder.append(", ");
            }
        }
        sBuilder.append("]");

        return sBuilder.toString();
    }

    /**
     * 判断链表是否相交
     * 
     * @tip 如果两个链表相交,则从相交的节点开始,后面的节点全部相同
     * @howtodo 判断尾节点是否相同
     * 
     * @param n1
     * @param n2
     * @return
     */
    public boolean isIntersect(Node n1, Node n2) {
    
    

        if (n1 == null || n2 == null) {
    
    
            return false;
        }

        while (n1.next != null) {
    
    
            n1 = n1.next;
        }

        while (n2.next != null) {
    
    
            n2 = n2.next;
        }

        return n1 == n2;
    }

    /**
     * 找到相交的第一个节点
     * @howtodo 使遍历两个链表的两个指针起点一致,然后第一次相等的地方就是相交的第一个节点。
     * @param n1
     * @param n2
     * @return
     */
    public Node getFirstMeetNode(Node n1, Node n2) {
    
    
        if (n1 == null || n2 == null)
            return null;

        Node tail1 = n1;
        int length1 = 1;
        while (tail1.next != null) {
    
    
            tail1 = tail1.next;
            length1++;
        }

        Node tail2 = n2;
        int length2 = 1;
        while (tail2.next != null) {
    
    
            tail2 = tail2.next;
            length2++;
        }

        if (tail1 != tail2)
            return null;

        Node t1 = n1;
        Node t2 = n2;

        if (length1 > length2) {
    
    
            int d = length1 - length2;
            while (d != 0) {
    
    
                t1 = t1.next;
                d--;
            }
        } else {
    
    
            int d = length2 - length1;
            while (d != 0) {
    
    
                t2 = t2.next;
                d--;
            }
        }

        while (t1 != t2) {
    
    
            t1 = t1.next;
            t2 = t2.next;
        }

        return t1;
    }

}

猜你喜欢

转载自blog.csdn.net/weixin_43394832/article/details/118229397