Java单链表和双链表的反转及实现队列、栈和双端队列

一、简介

1.1 什么是单链表和双链表?

单链表:值、next指针(指向下一个节点)
双链表:值、next指针(指向下一个节点)、last指针(指向上一个节点)

1.2 定义一个单链表

 /**
     * 单节点:值、next指针
     */
    public static class Node{
        public int value;
        public Node next;

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

1.3 定义一个双链表

  /**
     * 双节点:值、last指针、next指针
     */
    public static class DoubleNode{
        public int value;
        public DoubleNode last;
        public DoubleNode next;

        public DoubleNode(int data){
            this.value = data;
        }
    }

二、单链表和双链表的反转

2.1 单链表的反转

/**
     * 反转单链表
     * head
     *  |
     *  1 -> 2 -> 3 -> null
     *
     *  null <- 1 <- 2 <- 3
     *                    head
     * @param head
     * @return
     */
    public static Node reverseLinkedList(Node head){
        Node pre = null;
        Node next = null;
        /**
         * 反转单链表: 1 -> 2 -> 3 -> null
         * head为1时:
         * 1 的 next指针为 2
         * 反转时,先将next指针保留为next
         * 然后将 1 的next指针指向 null
         * 将当前head(1) 记录为 pre(上一个)
         * 将next (2) 记录为 head
         * -------------------
         * head为2时: pre 为 1
         * 将head(2)的next指针保留为next
         * 将head(2)的next指针指向pre
         * 将head(2)记录为pre
         * 将head(2)记录为next(3)
         * -------------------
         * head为3时:pre为2 同上,但是head(3)记录为next(null)
         * -------------------
         * head 为 null 结束循环,同时返回pre:此时head为3
         *
         */
        while (head != null){
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

2.2 双链表的反转

 /**
     * 反转双链表
     * head
     * null <- 1 <-> 2 <-> 3 -> null
     *
     * null <- 1 <-> 2 <-> 3 -> null
     *                     head
     * @param head
     * @return
     */
    public static DoubleNode reverseDoubleLinkedList(DoubleNode head){
        DoubleNode pre = null;
        DoubleNode next = null;
        while (head != null){
            /**
             * 首先head为 1 时: pre 为null
             * 此时记录head(1)的next(2)指针
             * 把 head(1)的next指针指向pre(null)
             * 把 head(1)的last指针指向next(2)
             * 将 pre 记录为 head(1)
             * 将 head 记录为 next(2)
             * ----------------------------------
             * 当head为2时:pre为1
             * 记录head(2)的 next(3)指针,
             * 将head(2)的next指向pre(1)
             * 将head(2)的last指针指向next(3)
             * 再将 pre(此时为1) 记录为 head  2
             * 将 head(此时为2) 记录为 next(3)
             * ----------------------------------
             * 当head为3时:pre为2
             * 记录 head(3)的next指针(null)
             * 将 head(3)的next指针指向pre (2)
             * 将 head(3)的last指针指向next (null)
             * 把 pre(此时为2)记录为 head(3)
             * 把 head(此时为3)记录为 next(null)
             * ----------------------------------
             * 当head为null, 结束循环。
             *
             */
            next = head.next;
            head.next = pre;
            head.last = next;
            pre = head;
            head = next;
        }
        return pre;
    }

2.3 测试

 public static void main(String[] args) {
        Node n1 = new Node(1);
        n1.next = new Node(2);
        n1.next.next = new Node(3);
        // 123 -> 321
        n1 = reverseLinkedList(n1);
        while (n1 != null){
            System.out.print(n1.value+" ");
            n1 = n1.next;
        }
        System.out.println();
        System.out.println("============");
        DoubleNode d1 = new DoubleNode(1);
        d1.next = new DoubleNode(2);

        d1.next.next = new DoubleNode(3);
        d1.next.last = d1;
        d1 = reverseDoubleLinkedList(d1);
        while (d1 != null){
            System.out.print(d1.value+" ");
            d1 = d1.next;
        }
    }

在这里插入图片描述

三、单链表结构实现队列

3.1 什么是队列

队列的特点:先进先出,正常的排队顺序。

3.2 单链表结构实现队列

 public static class Node<V>{
        public V value;
        public Node<V> next;

        public Node(V v){
            this.value = v;
            this.next = null;
        }
    }

 public static class MyQueue<V>{
        //三个属性
        //头
        private Node<V> head;
        //尾
        private Node<V> tail;
        //大小
        private int size;

        //无参构造
        public MyQueue(){
            this.head = null;
            this.tail = null;
            this.size = 0;
        }

        public boolean isEmpty(){
            return  size == 0;
        }

        public int size(){
            return size;
        }

        /**
         * 入队
         * @param value
         */
        public void offer(V value){
            Node<V> cur = new Node<>(value);
            if (tail == null){
                head = cur;
                tail = cur;
            }else {
                tail.next = cur;
                tail = cur;
            }
            size++;

        }

        /**
         * 弹出元素
         * @return
         */
        public V  poll(){
            V ans = null;
            if (head != null){
                ans = head.value;
                head = head.next;
                size--;
            }
            if (head == null){
                tail = null;
            }
            return ans;

        }

        /**
         * 查看队列尾部的元素
         * @return
         */
        public V peek(){
            V ans = null;
            if (head !=  null){
                ans = head.value;
            }
            return ans;
        }

    }

3.3 对数器验证

 /**
     * 队列 对数器
     */
    public static void testQueue() {
        MyQueue<Integer> myQueue = new MyQueue<>();
        Queue<Integer> test = new LinkedList<>();
        int testTime = 5000000;
        int maxValue = 200000000;
        System.out.println("测试开始!");
        for (int i = 0; i < testTime; i++) {
            if (myQueue.isEmpty() != test.isEmpty()) {
                System.out.println("Oops!");
            }
            if (myQueue.size() != test.size()) {
                System.out.println("Oops!");
            }
            double decide = Math.random();
            if (decide < 0.33) {
                int num = (int) (Math.random() * maxValue);
                myQueue.offer(num);
                test.offer(num);
            } else if (decide < 0.66) {
                if (!myQueue.isEmpty()) {
                    int num1 = myQueue.poll();
                    int num2 = test.poll();
                    if (num1 != num2) {
                        System.out.println("Oops!");
                    }
                }
            } else {
                if (!myQueue.isEmpty()) {
                    int num1 = myQueue.peek();
                    int num2 = test.peek();
                    if (num1 != num2) {
                        System.out.println("Oops!");
                    }
                }
            }
        }
        if (myQueue.size() != test.size()) {
            System.out.println("Oops!");
        }
        while (!myQueue.isEmpty()) {
            int num1 = myQueue.poll();
            int num2 = test.poll();
            if (num1 != num2) {
                System.out.println("Oops!");
            }
        }
        System.out.println("测试结束!");
    }

    public static void main(String[] args) {
        testQueue();
    }

在这里插入图片描述

四、单链表结构实现栈

4.1 什么是栈

栈的特点:先进后出,可以理解为弹夹,最先压入的子弹最后打出去。

4.2 单链表结构实现栈

   /**
     * 2. 单链表实现栈结构
     * @param <V>
     */
    public static class MyStack<V>{
        private Node<V>  head;
        private int size;

        public MyStack(){
            this.head = null;
            this.size = 0;
        }

        public boolean isEmpty(){
            return size == 0;
        }

        public int size(){
            return size;
        }

        /**
         * 入栈
         * @param value
         */
        public void push(V value){
            Node cur = new Node(value);
            if (head == null){
                //如果栈为空, 则head = cur
                head = cur;
            }else {
                //如果栈不为空,则cur的next指向当前head,并且head记录为cur
                cur.next = head;
                head = cur;
            }
            size++;
        }

        /**
         * 弹出栈元素
         * @return
         */
        public V pop(){
            V ans = null;
            if (head != null){
                //如果栈不为空,则直接返回head的value,并且head记录为head的next指针。
                ans = head.value;
                head = head.next;
                size--;
            }
            return ans;
        }

        public V peek(){
            return head.value == null ? null:head.value;
        }

    }

4.3 对数器验证

 /**
     * 栈 对数器
     */
     public static void testStack() {
        MyStack<Integer> myStack = new MyStack<>();
        Stack<Integer> test = new Stack<>();
        int testTime = 5000000;
        int maxValue = 200000000;
        System.out.println("测试开始!");
        for (int i = 0; i < testTime; i++) {
            if (myStack.isEmpty() != test.isEmpty()) {
                System.out.println("Oops!");
            }
            if (myStack.size() != test.size()) {
                System.out.println("Oops!");
            }
            double decide = Math.random();
            if (decide < 0.33) {
                int num = (int) (Math.random() * maxValue);
                myStack.push(num);
                test.push(num);
            } else if (decide < 0.66) {
                if (!myStack.isEmpty()) {
                    int num1 = myStack.pop();
                    int num2 = test.pop();
                    if (num1 != num2) {
                        System.out.println("Oops!");
                    }
                }
            } else {
                if (!myStack.isEmpty()) {
                    int num1 = myStack.peek();
                    int num2 = test.peek();
                    if (num1 != num2) {
                        System.out.println("Oops!");
                    }
                }
            }
        }
        if (myStack.size() != test.size()) {
            System.out.println("Oops!");
        }
        while (!myStack.isEmpty()) {
            int num1 = myStack.pop();
            int num2 = test.pop();
            if (num1 != num2) {
                System.out.println("Oops!");
            }
        }
        System.out.println("测试结束!");
     }

    public static void main(String[] args) {
        testStack();
    }

在这里插入图片描述

五、双链表结构实现双端队列

5.1 什么是双端队列

双端队列:即从队列头部和尾部都可以入队元素和出队元素。

5.2 代码实现

public static class MyDoubleQueue<V>{
        private Node<V> head;
        private Node<V> tail;
        private int size;

        public MyDoubleQueue(){
            head = null;
            tail = null;
            size = 0;
        }

        public boolean isEmpty(){
            return size == 0;
        }
        public int size(){
            return size;
        }

        /**
         * 从头部加元素
         * @param v
         */
        public void lpush(V v){
            Node<V> cur = new Node<>(v);
            //队列为空
            if (head == null){
                head = cur;
                tail = cur;
            }else {
                //队列不为空    head
                //     null     1   2   3   null
                //null   4(cur)   1   2   3   null
                //      head
                cur.next = head;
                head.last = cur;
                head = cur;
            }
            size ++;
        }

        /**
         * 从头部弹出元素
         * @return
         */
        public V lpop(){
            V ans = null;
            //队列为空
            if(head == null){
                return ans;
            }
            //队列不为空,弹出一个元素,队列大小-1
            size -- ;
            ans = head.value;
            //队列只有一个元素,弹出元素后,head和tail 置空
            if (head == tail){
                head = null;
                tail = null;
            }else {
                //队列中存在两个及以上元素,弹出头部元素后,head移动到next指针,并将此时的head的last置为null。
                head = head.next;
                head.last = null;
            }
            return ans;
        }

        /**
         * 从尾部加入元素
         * @param v
         */
        public void rpush(V v){
            Node<V> cur = new Node<>(v);
            if (tail == null){
                //如果队列为空
                head = cur;
                tail = cur;
            }else {
                //队列不为空                 tail
                // null     1       2       3       null
                // null     1       2       3       4       null
                //                                  tail
                cur.last = tail;
                tail.next = cur;
                tail = cur;
            }
            size ++;
        }
        public V rpop(){
            V ans = null;
            if (tail == null){
                return ans;
            }
            size --;
            ans = tail.value;
            if (head == tail){
                head = null;
                tail = null;
            }else {
                tail = tail.last;
                tail.next = null;
            }
            return ans;

        }
        
        public V lpeek(){
            return head == null ? null : head.value;
        }
        public V rpeek(){
            return tail == null ? null : tail.value;
        }

    }
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liu_Shihao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值