zoukankan      html  css  js  c++  java
  • 剑指Offer面试题:15.反转链表

    一、题目:反转链表

    题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

      链表结点定义如下,这里使用的是C#描述:

        public class Node
        {
            public int Data { get; set; }
            // 指向后一个节点
            public Node Next { get; set; }
    
            public Node(int data)
            {
                this.Data = data;
            }
    
            public Node(int data, Node next)
            {
                this.Data = data;
                this.Next = next;
            }
        }

    二、解题思路

    2.1 借助外部空间的解法一

      由于题目并没有要求必须原地反转,因此可以借助外部空间实现。这里可以将单链表储存为数组,然后按照数组的索引逆序进行反转。但是,此方式比较浪费空间,而且需要两次遍历,效率不占优势

      依据上面的思路,我们可以写出以下代码:

        public static Node ReverseList1(Node head)
        {
            if(head == null)
            {
                return null;
            }
    
            List<Node> nodeList = new List<Node>();
            while (head != null)
            {
                nodeList.Add(head);
                head = head.Next;
            }
    
            int startIndex = nodeList.Count - 1;
            for (int i = startIndex; i >= 0; i--)
            {
                Node node = nodeList[i];
                if (i == 0)
                {
                    node.Next = null;
                }
                else
                {
                    node.Next = nodeList[i - 1];
                }
            }
            // 现在头结点是原来的尾节点
            head = nodeList[startIndex];
            return head;
        }

    2.2 使用三个指针的高效解法二

      定义3个指针,分别指向当前遍历到的结点、它的前一个结点及后一个结点。在遍历过程中,首先记录当前节点的后一个节点,然后将当前节点的后一个节点指向前一个节点,其次前一个节点再指向当前节点,最后再将当前节点指向最初记录的后一个节点,如此反复,直到当前节点的后一个节点为NULL时,则代表当前节点时反转后的头结点了。

      整个过程只需遍历链表一次,效率提高不少,且需要的外部空间也较第一种方法要少很多,实现代码如下:

        public static Node ReverseList2(Node head)
        {
            if (head == null)
            {
                return null;
            }
    
            Node reverseHead = null;
            // 指针1:当前节点
            Node currentNode = head;
            // 指针2:当前节点的前一个节点
            Node prevNode = null;
    
            while(currentNode != null)
            {
                // 指针3:当前节点的后一个节点
                Node nextNode = currentNode.Next;
                if(nextNode == null)
                {
                    reverseHead = currentNode;
                }
                // 将当前节点的后一个节点指向前一个节点
                currentNode.Next = prevNode;
                // 将前一个节点指向当前节点
                prevNode = currentNode;
                // 将当前节点指向后一个节点
                currentNode = nextNode;
            }
    
            return reverseHead;
        }

    三、单元测试

    3.1 测试用例

      (1)为了方便对比,封装了一个用于将链表所有元素输出为字符串的方法GetNodeString()

        // 辅助方法:生成链表元素的字符串用于对比
        public string GetNodeString(Node head)
        {
            if (head == null)
            {
                return null;
            }
    
            StringBuilder sbResult = new StringBuilder();
            Node temp = head;
            while (temp != null)
            {
                sbResult.Append(temp.Data.ToString());
                temp = temp.Next;
            }
    
            return sbResult.ToString();
        } 
    View Code

      (2)功能测试、特殊输入测试

        // 01.输入的链表有多个结点
        [TestMethod]
        public void ReverseTest1()
        {
            Node node1 = new Node(1);
            Node node2 = new Node(2);
            Node node3 = new Node(3);
            Node node4 = new Node(4);
            Node node5 = new Node(5);
    
            node1.Next = node2;
            node2.Next = node3;
            node3.Next = node4;
            node4.Next = node5;
    
            Node newHead = ListHelper.ReverseList2(node1);
            Assert.AreEqual(GetNodeString(newHead), "54321");
        }
    
        // 02.输入的链表只有一个结点
        [TestMethod]
        public void ReverseTest2()
        {
            Node node1 = new Node(1);
    
            Node newHead = ListHelper.ReverseList2(node1);
            Assert.AreEqual(GetNodeString(newHead), "1");
        }
    
        // 03.输入NULL
        [TestMethod]
        public void ReverseTest3()
        {
            Node newHead = ListHelper.ReverseList2(null);
            Assert.AreEqual(GetNodeString(newHead), null);
        } 

    3.2 测试结果

      (1)测试通过情况

      (2)代码覆盖率

  • 相关阅读:
    java积累
    mybatis
    Netty
    springcloud相关笔记整理
    java基础总结笔记
    读书笔记-RocketMQ实战与原理解析
    读书笔记-kafka权威指南
    读书笔记-rabbitmq实战指南
    Centos 部署ServiceDesk
    IDEA将新建项目上传至GitLab
  • 原文地址:https://www.cnblogs.com/edisonchou/p/4769537.html
Copyright © 2011-2022 走看看