【问题标题】:Reverse a single chained List反转单个链表
【发布时间】:2009-09-16 10:39:31
【问题描述】:

我希望我使用了正确的术语。 我做了一个单链表。

class MyStack
{
    public Node Initial { get; set; }

    public MyStack()
    {
        Initial = null;
    }

    public void Push(int data)
    {
        var node = new Node { Data = data, Next = Initial };
        Initial = node;
    }

    public int Pop()
    {
        int res = Initial.Data;
        Initial = Initial.Next;
        return res;
    }

    public int Sum()
    {
        int sum = 0;
        Node currentNode = Initial;
        while (currentNode != null)
        {
            sum += currentNode.Data;
            currentNode = currentNode.Next;
        }
        return sum;
    }
    public int Count()
    {
        int count = 0;
        Node currentNode = Initial;
        while (currentNode != null)
        {
            count++;
            currentNode = currentNode.Next;
        }
        return count;
    }

    public void PrintAll()
    {     
        Node currentNode = Initial;
        while(currentNode != null)
        {
            Console.WriteLine("tmp.Data = " + currentNode.Data);
            currentNode = currentNode.Next;
        }
    }
}
public class Node
{
    public int Data;
    public Node Next;
}

意思是你可以这样做:

    var s = new MyStack();
    s.Push(5);
    s.Push(3);
    s.Push(7);
    s.PrintAll();
    Console.WriteLine("Sum: " + s.Sum());
    Console.WriteLine("Count: " + s.Count());

现在,我想尝试制作一个 Reverse 方法。这似乎有效:

public void Reverse()
{
    Node predesesor, location;
    location = Initial;
    predesesor = null;
    while(Initial != null)
    {
        Initial = Initial.Next;
        location.Next = predesesor;
        predesesor = location;
        location = Initial;
    }
    Initial = predesesor;
}

我几乎看不到它是如何工作的,而且很难维护。 这似乎更像是一种 hack。

您能提供任何帮助吗?

【问题讨论】:

  • 顺便说一句,如果您尝试在不推动的情况下弹出会发生什么?你可能想在那里打勾。
  • 是的,我知道 :) 这更像是一个个人练习,所以我可以更深入地了解这些事情是如何工作的。这不是我将在生产代码中使用的东西:)

标签: c# linked-list


【解决方案1】:

对我来说,这似乎不是一个 hack,而且我看不出有什么需要维护的(它是否正确,你还能用它做什么?)。如果您想弄清楚它是如何工作的,请在纸上“执行”每个步骤。绘制一个列表(例如 1 -> 3 -> 5 -> 7 -> 9 -> NULL),标出所有节点随时指向的位置并开始“单步执行”。

我想不出一种更简洁的方法来反转单链表。您需要对下一个节点(循环开始处的初始值)的引用,然后才能反转当前节点和前一个节点之间的链接。否则,您将无法在原始列表中继续前进。

你可以做的是修复变量的拼写,也许不在循环本身中使用 Initial(使用第三个变量,因此每个变量的作用更清晰)并且只将 Initial 设置为反向列表中的第一个节点最后。

所以,总而言之:

public void Reverse() {
    Node current = Initial, previous = null;
    while (current) {
        Node next = current.Next;
        current.Next = previous;
        previous = current;
        current = next;
    }
    Initial = previous;
}

【讨论】:

  • 维护意味着:任意程序员(比如说,两年后的你自己)需要能够依赖它。因此,正确还不够; 显然正确是必需的。文档、单元测试等可以弥补这一差距。微软为 .NET Framework 做了所有这些事情。
  • +1:好的变量名通常会使事情更清晰。这基本上与原始问题帖子中的相同,但更容易看到正在发生的事情。
  • 谢谢。我想我只是看了太久,只是迷路了。新的变量名称清理了很多。
  • 另一种解决方案是将链扁平化为 List<T> 并通过反转它来作弊
  • 您确实说过自己:P“作弊”
【解决方案2】:

一种解决方案是将其转换为双向链表,然后使用先前的节点属性向后工作:

public class Node
{
    public int Data;
    public Node Next;
    public Node Previous;
}

如果你想省点力气,框架中有already一个双向链表。

【讨论】:

  • 嗨。感谢您的建议,但我想先“掌握”一个单链表 :)
【解决方案3】:

你可以递归地做:

a->b->c->d

    a->null
     b->null
      c->null
      c<-d
     b<-c
    a<-b

a<-b<-c<-d

public void Reverse()
{
    Reverse(Initial);
}

private void Reverse(Node node)
{
    if(node != null && node.Next != null)
    {
        //go deeper
        Reverse(node.Next);
        //swap
        node.Next.Next = node
        node.Next = null;
    }
}

【讨论】:

  • 好的,它会工作,但更难看到发生了什么。它也可能更慢,如果堆栈中有很多项目,这可能很关键。
【解决方案4】:

您应该检查,而不是重新发明轮子,如果已经有可以使用的东西something from .Net Framework

例如,我会在这里使用LinkedListLinkedListNode。在其他情况下,您可能会选择QueueStack

【讨论】:

    【解决方案5】:

    如果您将其称为“nreverse”或“reverse in place”,那么任何值得 tuppence 的开发人员都会将其视为经典算法而不是 hack。

    它应该不需要太多维护,除了可能重命名任何拼写错误的变量。

    【讨论】:

      【解决方案6】:

      下面的代码可能更直观一点:

      public void Reverse()
      {
          MyStack reverse = new MyStack();
          while (Initial != null)
          {
             reverse.Push(this.Pop());
          }
          Initial = reverse.Initial;
      }
      

      (Reverse 是 MyStack 类的成员方法)。

      当然,与原始代码相比,它确实需要两倍的空间。

      【讨论】:

        【解决方案7】:
        stack s1
        s1.push_front(...)
        ...
        s1.push_front(...)
        

        /////////////////////////////////////// /////////

        void reverse(stack& to,stack_or_list& s )
            while(!s.empty()){
                to.push_front(s.pop_front());
            }
        }
        

        现在一系列 to.pop_fronts 可以让你得到你想要的

        stack_or_list 需要:pop_front 为空 到需求:push_front,pop_front

        【讨论】:

          猜你喜欢
          • 2016-09-29
          • 1970-01-01
          • 2018-10-16
          • 1970-01-01
          • 2020-02-06
          • 1970-01-01
          • 2012-10-08
          相关资源
          最近更新 更多