• 数据结构和算法-常见算法题


    参考:

    链表反转:

    https://blog.csdn.net/weixin_40807247/article/details/91435275

    https://blog.csdn.net/qq_33958946/article/details/84326965

    https://blog.csdn.net/qq_37117521/article/details/80808631

    链表反转

    理解单链表的反转(java实现)

    遍历法
    遍历法就是在链表遍历的过程中将指针顺序置换
    在这里插入图片描述

    //如何实现链表的反转
        public static Node ReverseIteratively(Node head){
            Node pre = null;
            Node next = null;
            while (head != null) {
                next = head.next;
                head.next = pre;
                pre = head;
                head = next;
            }
            return pre;
        }
    

    依旧是1->2->3->4
    准备两个空结点 pre用来保存先前结点、next用来做临时变量
    在头结点node遍历的时候此时为1结点
    next = 1结点.next(2结点)
    1结点.next=pre(null)
    pre = 1结点
    node = 2结点
    进行下一次循环node=2结点
    next = 2结点.next(3结点)
    2结点.next=pre(1结点)=>即完成2->1
    pre = 2结点
    node = 3结点
    进行循环…
    在这里插入图片描述
    递归法
    总体来说,递归法是从最后一个Node开始,在弹栈的过程中将指针顺序置换的。
    在这里插入图片描述
    递归实质上就是系统帮你压栈的过程,系统在压栈的时候会保留现场。
    我们来看是怎样的一个递归过程:1->2->3->4
    程序到达Node newHead = reverse(head.next);时进入递归
    我们假设此时递归到了3结点,此时head=3结点,temp=3结点.next(实际上是4结点)
    执行Node newHead = reverse(head.next);传入的head.next是4结点,返回的newHead是4结点。
    接下来就是弹栈过程了
    程序继续执行 temp.next = head就相当于4->3
    head.next = null 即把3结点指向4结点的指针断掉。
    返回新链表的头结点newHead

    //递归实质上就是系统帮你压栈的过程,系统在压栈的时候会保留现场
        public Node reverse(Node head) {
            //递归
            if (null == head ||null  == head.next)
                return head;
            Node temp = head.next;
            Node newHead = reverse(head.next);
            temp.next = head;
            head.next = null;
            return newHead;
        }
    @Test
        public void testCase() {
            LinkedList list = new LinkedList();
            System.out.println("测试头插法");
            list.addNodeHead(4);
            list.addNodeHead(3);
            list.display();
            list.addNodeHead(2);
            list.addNodeHead(1);
            /*list.display();
            list.addNodeTail(4);
            list.display();
            System.out.println("测试某个位置删除法");
            list.deleteNode(3);
            list.display();
            System.out.println("测试删除重复数据前");
            list.addNodeHead(1);
            list.display();
            System.out.println("测试删除重复数据");
            list.deleteDuplecate1(list.head);
            list.display();
            System.out.println("测试删除重复数据1");
            list.addNodeIndex(2,1);
            list.display();
            list.deleteDuplecate(list.head);*/
            list.display();
            System.out.println("链表的反转");
            //Node node = LinkedList.ReverseIteratively(list.head);
            Node node1 = list.reverse(list.head);
            while (node1 != null){
                System.out.println(node1.data);
                node1 = node1.next;
            }
        }

    在这里插入图片描述

    java经典面试题:单链表反转问题详解(含递归法)

    java经典面试题:单链表反转问题,有两种方法,一种为循环遍历法,一种递归法。
    1、循环遍历法
    在这里插入图片描述
      首先设置三个节点,把当前节点的下一节点指向它前面的节点,此时你会发现指针链会断,所以要先把它后面一个节点用nextNode保存下来,之后把节点向后移动遍历即可。
      
    代码如下:

    //定义单链表节点类
    public class ListNode {
    		int value;
    		ListNode next;
    		
    		public ListNode() {
    			this.value=0;
    			this.next=null;
    		}
    		public ListNode(int value) {
    			this.value=value;
    		}
    }
    	
    //定义链表反转方法
    public ListNode reverseList(ListNode root) {
    		if(root==null)return root;
    		ListNode newhead=null;  //反转后的新链表头结点
    		ListNode preNode = null; //前一节点
    		ListNode nextNode=null; //下一节点
    		ListNode curNode=root; //当前节点
    		while(curNode.next!=null) {
    			nextNode=curNode.next; //保存当前节点的下一节点
    		    curNode.next=preNode; //使当前节点指向前一节点
    		    preNode=curNode;  //把前一节点往后移
    		    curNode=nextNode; //把当前节点往后移
    		}
    		newhead=curNode; 
    		return newhead;
    	}

    2、递归法
    如果当前节点或者当前节点的下一节点为空,直接返回该节点;
    否则使该节点的后一节点指向该节点,以此递归。

    public BinaryNode reverseList2(BinaryNode root) {
    		if(root==null||root.next==null)return root;
    		BinaryNode nextNode=root.next; //得到当前节点的下一节点
    		root.next=null; //打断当前指针链
    		BinaryNode re=reverseList2(nextNode); //每次递归下一节点进行反转
    		nextNode.next=root; //反转指针域
    		return re;
    	}

    使用递归反转链表

    链表反转:

    (图1)

    把问题规模减小,并且减小的量为1

    (图2)

    假设我们的程序能够正常的反转:则反转后为

    (图3)

    反转后,1元素并没有任何操作,所以反转1的next仍然指向2,

    (图4)

    假设2开头的链表已经反转成功,接下来只要将2的next指向1,

    (图5)

    而1的next指向null即可。

    (图6)

    看似复杂的问题,把如此多的指针反过来指,其实只要将两个节点反过来即可。

    代码如下:

    package com.sise.recursion;
     
    import java.util.ArrayList;
    import java.util.Arrays;
     
    public class LinkedListReverser {
     
        /*
         * 反转一个链表
         * head为待反转链表的头结点
         * @return 反转后的链表头结点,当然该链表也是以null结尾
         */
        public Node reverseLinkedList(Node head) {
            
            /*
             *特殊处理
             */
    //        //空链表,sise==0
    //        if(head==null){
    //            return null;
    //        }
    //        //只有一个结点的时候,size==1
    //        if(head.getNext()==null){
    //            return head;
    //        }
            
            //把上两个特殊情况合起来
            if(head==null||head.getNext()==null){
                return head;
            }
            
            
            
            //假设函数能够反转链表,返回头结点
            //---------------此处head有可能是null,head。getNext()有可能是null-----------
            Node newHead=reverseLinkedList(head.getNext());
            //此时如图4状态,1的getNext就是第二个结点2,
            //把第二结点2的next指向head则实现把2的指针指向1,如图5
            //------------此处的getNext()有可能是null------
            head.getNext().setNext(head);
            head.setNext(null);//最后指向null,如图6
            return newHead;
        }
        public static void main(String[] args) {
            LinkedListCreator creator=new LinkedListCreator();
            LinkedListReverser reverser=new LinkedListReverser();
            
            
            ArrayList arrayList=new ArrayList<>();
            
            Node.printLinkedList(
                    reverser.reverseLinkedList(creator.createLinkedList(arrayList))
                    );
            Node.printLinkedList(
                    reverser.reverseLinkedList(creator.createLinkedList(Arrays.asList(1)))
                    );
            Node.printLinkedList(
                    reverser.reverseLinkedList(creator.createLinkedList(Arrays.asList(1,2,3,4,5)))
                    );
     
        }
     
    }
    package com.sise.recursion;
     
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
     
     
    public class LinkedListCreator {
     
        /*
         * 创建一个链表
         * @return 链表的头结点,返回链表的最后一个结点的getNext()==null.
         */
        public Node createLinkedList(List<Integer> data){
            //假设传入空的List
            if(data.isEmpty()){
                return null;
            }
            
            //取出传入数据的第一个结点
            Node firstNode=new Node(data.get(0));
            //取走一个元素后,从第二个元素创建一个链表,
            //因为返回的是Node,所以用Node来接收
            //假设传入来的List有一个元素,则走到这里时sublist传入的两个参数相等
            //但是sublist函数的定义可以看到fromIndex==toIndex时,返回null
            /*
             *  <tt>fromIndex</tt> and <tt>toIndex</tt> are equal, the returned list is
             */
            //与我们期望返回值一致
    //        Node headOfSublistNode=
    //                createLinkedList(data.subList(1, data.size()));
    //        //第一个结点的next指向规模缩小的链表返回来的头结点
    //        firstNode.setNext(headOfSublistNode);
            //上面两行代码清理成如下代码
            firstNode.setNext(createLinkedList(data.subList(1, data.size())));
            return firstNode;
            
        }
        public static void main(String[] args) {
            LinkedListCreator creator=new LinkedListCreator();
            
            ArrayList arrayList=new ArrayList<>();
            
            Node.printLinkedList(
                    creator.createLinkedList(arrayList)
                    );
            Node.printLinkedList(
                    creator.createLinkedList(Arrays.asList(1))
                    );
            Node.printLinkedList(
            creator.createLinkedList(Arrays.asList(1,2,3,4,5))
        );
        }
     
    }
    package com.sise.recursion;
     
    public class Node {
        
        private final int value;//用户定义之后就不能修改
        private Node next;
        
        public Node(int value){
            this.value=value;
            this.next=null;//这样建立出来的结点都是单点Node
        }
        
        public Node getNext() {
            return next;
        }
        public void setNext(Node next) {
            this.next = next;
        }
        public int getValue() {
            return value;
        }
        //打印函数
        public static void printLinkedList(Node head) {
            while(head!=null){
                System.out.print(head.getValue());;
                System.out.print(" ");
                head=head.getNext();
            }
            System.out.println();
        }
        
    }

    运行结果:

  • 相关阅读:
    利用高斯金字塔制作图像显著图
    python实现图像高斯金字塔
    使用差分金字塔提取图像边缘 python实现
    使用色彩追踪和形态学运算得到图像中感兴趣区域
    图像掩膜讲解
    图像色彩追踪
    手动绘制方向梯度直方图(HOG)
    Zhang-Suen 图像细化算法python实现
    hilditch图像细化算法python实现
    P2256 一中校运会之百米跑
  • 原文地址:https://www.cnblogs.com/xuwc/p/13934223.html
Copyright © 2020-2023  润新知