反转单个链表

时间:2009-09-16 10:39:32

标签: c# linked-list

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

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());

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

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;
}

我几乎无法看到它是如何工作的,而且很难维持。 它似乎更像是一个黑客而不是其他任何东西。

你能提供任何帮助吗?

7 个答案:

答案 0 :(得分:5)

对我来说这似乎不是一个黑客,我不知道有什么可以维护(它是正确与否,你还能用它做什么?)。如果你想弄清楚它是如何工作的,那就在纸上“执行”每一步。绘制一个列表(例如1 - > 3 - > 5 - > 7 - > 9 - > NULL),标记所有节点在任何时间指向的位置并开始“单步”。

我想不出一个更简洁的方法来反转单链表。在转换当前节点和上一个节点之间的链接之前,需要引用下一个节点(循环开始时的Initial)。否则你将无法在原始列表中继续前进。

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

所以,总而言之:

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

答案 1 :(得分:4)

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

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

如果您想节省一些精力,框架中有already个双向链表。

答案 2 :(得分: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;
    }
}

答案 3 :(得分:1)

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

例如,我会将LinkedListLinkedListNode放在一起。在其他情况下,您可以选择QueueStack

答案 4 :(得分:0)

如果你称之为“nreverse”或“反向就位”,那么任何值得拥抱的开发者都会将其视为经典算法而非黑客攻击。

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

答案 5 :(得分:0)

以下代码可能更直观一些:

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

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

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

答案 6 :(得分:0)

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