数据结构重点内容

发布于:2025-08-05 ⋅ 阅读:(16) ⋅ 点赞:(0)

一.单链表

基于java实现:

// 节点类
class Node{
    int data;
    Node next;


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

    public Node(int data){
        this.data = data;
        this.next = null;
    }
}
// 链表类
public class SinglyLinkedList {
    private Node head;

    public SinglyLinkedList() {
        head = null;
    }

    // 向链表结尾插入数据
    public void addNode(int data) {
        Node node = new Node(data);
        if (head == null) {
            head = node;
        }
        else {
            Node temp = head;
            while(temp.next != null) {
                temp = temp.next;
            }
            temp.next = node;
        }
    }

    // 获取链表长度
    public int length(){
        Node temp = head;
        int length = 0;
        while (temp != null) {
            length++;
            temp = temp.next;
        }
        return length;
    }

    // 删除下标为 n 的节点 ,这里假设头节点算第1个节点
    public boolean deleteNode(int n) {
        int length = length();
        if(n<1 || n>length) return false;

        if(n==1) {
            head = head.next;
            return true;
        }

        // 找到要删除节点的前一个节点
        Node temp = head;
        int count = 1;
        while(count<n-1) {
            count++;
            temp = temp.next;
        }
        // 删除节点(无论是中间节点还是尾节点)
        temp.next = temp.next.next;
        return true;
    }

    // 在不知道头节点的情况下删除指定节点
    public boolean deleteAnyNode(Node n){
        // 该节点为空或者是尾节点,就无法删除
        if(n==null || n.next==null) return false;
        // 将下一个节点的数据复制到当前节点
        n.data=n.next.data;
        // 跳过下一个节点(相当于删除了当前节点的数据)
        n.next = n.next.next;
        return true;
    }

    public void printList(){
        Node temp = head;
        while(temp!=null){
            System.out.print(temp.data+" ");
            temp = temp.next;
        }
    }

    // 链表反转,迭代法
    public Node reverseList(Node head){
        if(head==null || head.next==null) return head;
        Node prev = null;   // 前一个节点
        Node curr = head;   // 当前节点
        Node next = null;   // 下一个节点
        while(curr!=null){
            next = curr.next;   // 保存下一个节点
            curr.next = prev;   // 反转当前节点的指向 ,这一步是核心,上一步的顺序不能交换
            prev = curr;        // 移动prev指针
            curr = next;        // 移动current指针
        }
        head = prev;            // 反转后prev成为新的头节点
        return head;
    }

    // 寻找链表中间节点
    public Node findMid(Node head){
        if(head == null ) return null;
        Node fast = head;
        Node slow = head;
        // 如果长度为奇数,则fast在最后一个节点停下,若为偶数,则在倒数第二个节点停下
        while(fast.next!=null && fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }

    // 查找链表倒数第k个元素
    public Node findK(Node head,int k){
        if(head == null || k<1) return null;
        Node fast = head;
        Node slow = head;
        for(int i=0;i<k;i++){
            // 如果k大于链表长度,提前返回空
            if(fast==null) return null;
            fast = fast.next;  // 快指针移动k步
        }
        while(fast!=null){   // 快慢指针之间应该相差k个节点,如k=2 slow在倒数第二个,则fast在尾节点之后(null)
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }

    // 对链表排序,基于归并排序
    public void mergeSort(){
        head = mergeSort(head);
    }
    private Node mergeSort(Node head){
        // 空链表或单个链表无需排序
        if(head==null || head.next==null) return head;

        // 先找中间节点,用来拆分链表
        Node mid = findMid(head);
        Node rightHead = mid.next;
        // 切断链表
        mid.next = null;

        // 分别对左右两端链表递归调用
        Node left = mergeSort(head);
        Node right = mergeSort(rightHead);

        return merge(left,right);
    }
    // 合并两段链表
    private Node merge(Node left,Node right){
        Node res = new Node(0);
        Node curr = res;
        // 合并处理
        while(left!=null&&right!=null){
            if(left.data<right.data){
                curr.next = left;
                left = left.next;
            }else{
                curr.next = right;
                right = right.next;
            }
            curr = curr.next;
        }
        // 处理剩余节点
        if(left!=null){
            curr.next = left;
        }
        if(right!=null){
            curr.next = right;
        }
        return res.next;
    }

    // 删除链表的重复节点,保留1个节点,前提链表有序
    public void deleteDuplicates(Node head){
        if(head==null || head.next==null) return;
        Node curr = head;
        while(curr!=null && curr.next!=null){
            if(curr.data==curr.next.data){
                curr.next = curr.next.next;
            }else{
                curr = curr.next;
            }
        }
    }

    // 判断链表是否有环,如有则找到入口
    public boolean isLoop(Node head){
        Node fast = head;
        Node slow = head.next;
        while(fast!=slow){
            if(fast==null || fast.next==null) return false; // 能到末尾说明无环
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }

    // 确定有环,找到环的入口
    public Node findStart(Node head){
        // 先找到快慢指针第一次相遇的节点
        Node fast = head;
        Node slow = head;
        while(fast!=slow){
            slow = slow.next;
            fast = fast.next.next;
        }
        // 找到后将slow移动到头节点
        slow = head;
        while(slow!=fast){
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到