在C#中反转单个链表

Nem*_*emo 27 c# reverse singly-linked-list

我试图扭转链表.这是我提出的代码:

 public static void Reverse(ref Node root)
 {
      Node tmp = root;
      Node nroot = null;
      Node prev = null;

      while (tmp != null)
      {
          //Make a new node and copy tmp
          nroot = new Node();    
          nroot.data = tmp.data;

          nroot.next = prev;
          prev = nroot;   
          tmp = tmp.next;
       }
       root = nroot;            
  }
Run Code Online (Sandbox Code Playgroud)

它运作良好.想知道是否有可能避免创建新节点.想对此有所建议.

Eri*_*ert 55

这个问题被问了很多.当我多年前在我的采访中被问到这个问题时,我的理由如下:单链表基本上是一个堆栈.因此,反转链表是堆栈上的一个简单操作:

newList = emptyList;
while(!oldList.IsEmpty())
    newList.Push(oldList.Pop());
Run Code Online (Sandbox Code Playgroud)

现在你所要做的就是实现IsEmpty和Push and Pop,它们是一行或两行的顶部.

我在大约二十秒内把它写出来,面试官在那一点似乎有些困惑.我想他希望我花大约20分钟做大约20秒的工作,这对我来说一直都很奇怪.

  • @AdamRackis:它也是语法上完美的JavaScript和C++,也可能是其他一些语言.:) (7认同)
  • 现在,当然,在正确的实现中,我们将成为好公民,并抛出一个空堆栈,我们将在不可变堆栈上实现`IsEmpty`,以及许多其他功能,这将使这段代码更长.但是,使任何代码强大且功能齐全,使其更长.我的目的不是为了打造最短的可靠解决方案.需要指出的是,当您将编码移动到一个语义级别时,代码会变得更短,更容易理解*它在哪里计算*. (3认同)
  • @Markus:首先,我对此表示怀疑.其中一些解决方案很长.每个堆栈操作都是几行.而对于这个极其微不足道的成本,你得到一个堆叠ADT.**关于抽象数据类型操作的代码的原因,而不是指针和变量,您的代码将变得更容易理解**.根据代码高尔夫来判断候选人的面试官正在寻找错误的信号. (2认同)
  • @Markus:在这里,让我们将其放入注释中。我们将首先实现一个不可变的链表:`class Node <T> {public T Head {get; 私人套装;} public Node <T>尾巴{get; 私人套装;} public static Node <T> Empty = new Node <T>(); 私有Node(){} public Node <T> Push(T t)=> new Node <T> {Head = t,Tail = this}}`现在我们实现了一个可变的`class List <T> {private Node < T> n = Node <T> .Empty; 公共布尔IsEmpty => n == Node <T> .Empty; 公共无效Push(T t){n = n.Push(t); } public T Pop(){T h = n.Head; n。尾 返回h; }}`,我们完成了。 (2认同)
  • @Markus:现在我们有可变和不可变堆栈。每个方法都在一到三行代码之间,我们可以根据抽象操作来推理列表的行为,而不是根据它如何使用引用和属性来实现。这不仅比这里发布的任何其他解决方案功能更全面,而且比大多数解决方案*短*,因为显然简洁是你关心的事情。 (2认同)

das*_*ght 49

Node p = root, n = null;
while (p != null) {
    Node tmp = p.next;
    p.next = n;
    n = p;
    p = tmp;
}
root = n;
Run Code Online (Sandbox Code Playgroud)


ras*_*asx 6

几年前,我错过了一个时髦的LA-娱乐公司ASP.NET MVC开发人员的职位,因为我无法回答这个问题:((这是一种淘汰非计算机科学专业的方法。)所以我很尴尬地承认我花了很长时间才在LINQpad中使用实际的方法解决这个问题LinkedList<T>

var linkedList = new LinkedList<int>(new[]{1,2,3,4,5,6,7,8,9,10});
linkedList.Dump("initial state");

var head = linkedList.First;
while (head.Next != null)
{
    var next = head.Next;
    linkedList.Remove(next);
    linkedList.AddFirst(next.Value);
}

linkedList.Dump("final state");
Run Code Online (Sandbox Code Playgroud)

只读LinkedListNode<T>.Next属性LinkedList<T>在这里非常重要。(鼓励非comp-sci人研究数据结构的历史-我们应该问一个问题,链表从何而来-为什么会存在?)

  • 像您一样,上个星期我也错过了ASP.NET MVC开发人员的职位,因为存在关于反转链接列表的相同问题: (2认同)
  • 好一个!尽管反转链表是一个普遍的问题,但是与说C ++或Java相比,实现C#是一个不同而棘手的问题,因为C#的节点不允许下一步设置。因此,您必须全力以赴,然后再考虑删除! (2认同)

Chr*_*Wue 5

您无需复制.一些伪代码:

prev = null;
current = head;
next = current->next;

(while next != null)
    current->next=prev
    prev=current
    current=next
    next=current->next
Run Code Online (Sandbox Code Playgroud)


Jac*_*tti 5

这在 Leetcode 上表现得很好。

public ListNode ReverseList(ListNode head) {

        ListNode previous = null;
        ListNode current = head; 
        while(current != null) {
            ListNode nextTemp = current.next;
            current.next = previous;
            previous = current;
            current = nextTemp;
        }

        return previous;
    }     
Run Code Online (Sandbox Code Playgroud)