算法与数据结构新手班第4节

本文主要探讨了单链表和双链表的概念,并通过一系列题目讲解了如何进行链表反转、使用链表实现队列和栈,以及双端队列的构建。此外,还涉及到了K个节点的组内逆序调整和链表中的数学运算问题,如两数相加和有序链表合并。

单链表与双链表

单链表:两个属性分别为值,和下一个节点的地址

双链表:三个属性分别为值,上一个节点的地址和下一个节点的地址

题目一:单链表的反转

public class reverseLinkedList {
    public static class Node {
        public int vaule;
        public Node next;

        public Node(int vaule) {
            this.vaule = vaule;
        }

    }
    static Node reverseLinkedList(Node head) {
        Node pre = null;
        Node next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }
    public static void main(String[] args) {
        Node head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        //如果仅像下面这样操作,head的vaule还是1,因为引用的传递,在上面的reverseLinkedList方法中如果在head = next;后面对head的属性进行操作,改变的实际是next的属性,因为head指向next
        //reverseLinkedList(head);
        //System.out.println(head.vaule);//head.vaule=1
        head = reverseLinkedList(head);
        System.out.println(head.vaule);
        System.out.println(head.next.vaule);
        System.out.println(head.next.next.vaule);
    }
}

JVM的释放:在上面这种链表中,只有一个对象head,如果先改变了head的指向,而不改变head,原先head的所有指向都会消失,这叫做JVM的释放

题目二:双链表的反转

public class reverseDoubleList {
    public static class Node {
        public int vaule;
        public Node next;
        public Node last;

        public Node(int vaule) {
            this.vaule = vaule;
        }
    }

    static Node reverseDoubleList(Node head) {
        Node pre = null;
        Node next = null;
        while (head != null) {
            //记录下一个位置
            next = head.next;
            //改变head的last
            head.last = next;
            //改变head的next
            head.next = pre;
            //改变pre位置
            pre = head;
            //改变head位置
            head = next;

        }
        return pre;
    }

    public static void main(String[] args) {
        Node head = new Node(1);
        head.next = new Node(2);
        head.next.last = head;
        head.next.next = new Node(3);
        head.next.next.last = head.next;
        head = reverseDoubleList(head);
        System.out.println(head.vaule);
        System.out.println(head.next.vaule);
        System.out.println(head.next.next.vaule);
    }
}

题目三:用单链表实现队列

接收一些数据(为队列),然后按接收的顺序输出

public class LinkedListToQueue {
    public static class Node<E> {
        E vaule;
        Node next;


        public Node(E vaule) {
            this.vaule = vaule;

        }

    }
    static class MyQueue<V>{
        Node<V> head;
        private Node<V> tail;

        public MyQueue() {
        }

        public void get(V v){
            Node<V> node = new Node<>(v);
            if(head != null){
                tail.next = node;
            }else{
                head = node;
            }
            tail = node;
        }
        public V peek(){
            V ans = head.vaule;
            head = head.next;
            //防止产生脏数据
            if(head == null){
                tail = null;
            }
            return ans;
        }
    }

    public static void main(String[] args) {
        MyQueue<Integer> mq = new MyQueue<>();
        mq.get(1);
        mq.get(2);
        mq.get(3);
        System.out.println(mq.peek());
        System.out.println(mq.peek());
        System.out.println(mq.peek());
    }
}

脏数据:从目标中取出的数据已经过期、错误或者没有意义,这种数据就叫做脏数据。

题目三:用单链表实现栈

接收一些数据(为栈),然后按接收的倒序输出

public class LinkedListToStack {
    static class Node<E> {
        E vaule;
        Node next;

        Node() {
        }

        Node(E vaule) {
            this.vaule = vaule;
        }

        static class MyStack<V> {
            Node<V> head;

            MyStack() {
            }

            void put(V v) {
                Node<V> node = new Node<>(v);
                node.next = head;
                head = node;
            }

            V peek() {
                V ans = head.vaule;
                head = head.next;
                return ans;
            }
        }
    }

    public static void main(String[] args) {
        //引用类型的传递(当被指向的对象改变时(属性改变不算),指向对象会代替原位置)
        Node<Integer> node = new Node<>(1);
        Node<Integer> node2 = new Node<>(2);
        Node<Integer> node3 = new Node<>(3);
        node = node2;
        System.out.println(node.vaule);//2
        node2.vaule = 1;
        System.out.println(node.vaule);//1
        System.out.println(node == node2);//true
        node2 = node3;
        System.out.println(node == node2);//false

        Node.MyStack<String> ms = new Node.MyStack<>();
        ms.put("我是");
        ms.put("中国人");
        System.out.println(ms.peek());
        System.out.println(ms.peek());
    }
}

题目四:用双链表结构实现双端队列

可以在队列两端加元素,读取元素

public class DoubleLinkedListToDeque {
    class Node<V> {
        public V vaule;
        public Node<V> last;
        public Node<V> next;

        public Node(V v) {
            vaule = v;
            last = null;
            next = null;
        }
    }

    class MyDeque<V> {
        private Node<V> head;
        private Node<V> tail;

        public MyDeque() {
        }


        void pushHead(V v) {
            Node<V> node = new Node<>(v);
            if (head == null) {
                tail = node;
            } else {
                head.last = node;
                node.next = head;
            }
            head = node;
        }

        void pushTail(V v) {
            Node<V> node = new Node<>(v);
            if (tail == null) {
                head = node;
            } else {
                tail.next = node;
                node.last = tail;
            }
            tail = node;
        }

        V pollHead() {
            V ans = null;
            if (head != null) {
                ans = head.vaule;
                head = head.next;
                if (head != null) {
                    head.last = null;
                } else {
                    tail = null;
                }
            }
            return ans;
        }

        V pollTail() {
            V ans = null;
            if (tail != null) {
                ans = tail.vaule;
                tail = tail.last;
                if (tail != null) {
                    tail.next = null;
                } else {
                    head = null;
                }
            }
            return ans;
        }
    }
}

双链表不会自动释放

题目五:K个节点的组内逆序调整(Hard)

给定一个单链表的头节点head,和一个正数k

实现每k个数的内部逆序,如果最后一组不够k个就不调整

测试链接

    public static ListNode reverseKGroup(ListNode head, int k) {
        ListNode start = head;
        ListNode end = getKGroupEnd(start, k);
        if (end == null) {
            return head;
        }
        // 第一组凑齐了!
        head = end;
        reverse(start, end);
        // 上一组的结尾节点
        ListNode lastEnd = start;
        while (lastEnd.next != null) {
            start = lastEnd.next;
            end = getKGroupEnd(start, k);
            if (end == null) {
                return head;
            }
            reverse(start, end);
            lastEnd.next = end;
            lastEnd = start;
        }
        return head;
    }

    public static ListNode getKGroupEnd(ListNode start, int k) {
        while (--k != 0 && start != null) {
            start = start.next;
        }
        return start;
    }

    public static void reverse(ListNode start, ListNode end) {
        end = end.next;
        ListNode pre = null;
        ListNode cur = start;
        ListNode next = null;
        while (cur != end) {
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        start.next = end;
    }

单链表,因为JVM释放,所以方法的返回值一定不能是void

题目六:链表中的两数相加

测试链接

public class ListNode {
    int val;
    ListNode next;

    ListNode() {
    }

    ListNode(int val) {
        this.val = val;
    }

    ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
}

class Solution {

    public static int getlength(ListNode node) {
        int size = 0;
        while (node != null) {
            size++;
            node = node.next;
        }
        return size;
    }

    public static ListNode reverse(ListNode head) {
        ListNode next = null;
        ListNode pre = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

    public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int len1 = getlength(l1);
        int len2 = getlength(l2);
        l1 = reverse(l1);
        l2 = reverse(l2);
        ListNode l = len1 > len2 ? l1 : l2;
        ListNode s = len1 > len2 ? l2 : l1;
        int carry = 0;
        int num = l.val + s.val + carry;
        l.val = num % 10;
        ListNode ans = l;
        ListNode last = null;
        carry = num / 10;
        s = s.next;
        last = l;
        l = l.next;
        while (s != null) {
            num = l.val + s.val + carry;
            l.val = num % 10;
            carry = num / 10;
            s = s.next;
            last = l;
            l = l.next;

        }
        while (l != null) {
            num = l.val + carry;
            l.val = num % 10;
            carry = num / 10;
            last = l;
            l = l.next;
        }
        if (carry != 0) {
            last.next = new ListNode(1);
        }
        return reverse(ans);
    }
}

题目七: 合并两个有序链表

测试链接

public class ListNode {
    int val;
    ListNode next;

    ListNode() {
    }

    ListNode(int val) {
        this.val = val;
    }

    ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
}

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list1 == null || list2 == null) {
            return list1 == null ? list2 : list1;
        }
        ListNode cur = list1.val > list2.val ? list2 : list1;
        ListNode ans = cur;
        ListNode head2 = cur == list1 ? list2 : list1;
        ListNode head = cur.next;
        while (head != null && head2 != null) {
            if (head.val > head2.val) {
                cur.next = head2;
                head2 = head2.next;
            } else {
                cur.next = head;
                head = head.next;
            }
            cur = cur.next;
        }
        cur.next = head == null ? head2 : head;
        return ans;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值