【问题标题】:Move node to beginning of singly linked list将节点移动到单链表的开头
【发布时间】:2014-08-06 18:05:33
【问题描述】:

在 Pascal 中,当我有一个带有这样定义的节点的单链表时,

pNode = ^Node;
Node = record
    data : data;
    next : pNode;
end;

当我像这样遍历列表时

while y<>z do begin
        if y^.data < x^.data then begin
          { HERE I WOULD LIKE TO MOVE y IN FRONT OF X }
        end;
        y:=y^.next;
end;

其中 x 是枢轴(列表的开头),y 是“索引”,z 是列表的尾部(结尾)(是的,我正在尝试对单链表执行快速排序)。我将如何完成评论中的任务?

我做了程序insertAfter

procedure List.insertAfter(n : pNode; var what : data);
var newn : pNode;
begin
  new(newn);
  newn^.data := what;
  newn^.next := n^.next;
  n^.next := newn;
end;

insertInstead

procedure List.insertInstead(n : pNode; var what : data);
begin
    List.insterAfter(n, n^.data);
    n^.data:=what;
end;

同样deleteAfter(n : pNode)

procedure List.deleteAfter(n : pNode);
var q : pNode;
begin
    q := n^.next;
    n^.next := n^.next^.next;
    dispose(q);
end;

delete(n : pNode)

procedure List.delete(n : pNode);
begin
    if n^.next <> tail then begin
        n^.data := n^.next^.data;
        deleteAfter(n);
    end
    else begin
        dispose(tail);
        tail:=n;
        tail^.next := nil;
    end;
end;

现在当我放入迭代时,而不是评论

list.insertInstead(x,y^.data);
list.delete(y);

,它不起作用,大概是因为y^.next现在没有指向与移动之前相同的节点。

所以问题是:如何将节点移动到开头,y^.next 仍然指向同一个节点?

PS.:我已经尝试过明显的:使用和辅助变量来存储移动前y的实际值,但它似乎随着y而变化。

这里是原始代码:StackListQuicksort

【问题讨论】:

  • List.delete 中似乎有错误/错误类型。在“deleteAfter(p)”行中,“p”是什么?
  • @Penguino 已编辑。但这不是问题(我正在翻译代码)
  • List.delete 中还有另一个“错字/错误”。你写“n^.data := n^.next^.next;”这不应该是“n^.data := n^.next^.data;”吗?除非您复制真实代码(或注意避免“翻译”中的错误,否则很难说出原始代码的作用。
  • @Penguino 是的,现在应该也是。现在我确定这是绝对正确的。
  • @Penguino 我还添加了指向原始代码的链接。

标签: algorithm sorting linked-list pascal quicksort


【解决方案1】:

也许最简单的方法就是改变(交换)节点的值。

{ HERE I WOULD LIKE TO MOVE y IN FRONT OF X }
tmp := x^.data
x^.data := y^.data
y^data := tmp

更新:这是类似的答案:https://stackoverflow.com/a/1536046/2490538

兹德拉维姆。

【讨论】:

  • 这是我尝试的第一件事,但它不起作用。 stackoverflow.com/questions/24214256/…
  • 如果我理解得很好,您想按值对节点进行排序。
  • 这是最终目标,但这里的问题是快速排序中的除法步骤,我想将所有小于第一个(枢轴)的元素放在它前面(之前)。跨度>
  • 如何将节点数据保存到数组中,对数组进行排序并将这些值返回到列表中。如果使用节点操作,则内​​存分配过多。使用内置的快速排序。)
  • 是的,这是一个解决方案。但是首先使用列表的全部意义在于,与数组不同,列表是一个动态数据结构。所以你认为这是不可能的?
【解决方案2】:

我想我可能会看到问题所在。插入代码的第一行

 list.insertInstead(x,y^.data);

工作正常。它在 x 之后立即放置一个新节点并用 y 的数据填充它(因此您现在有效地在节点 x 之后拥有节点 y 的副本。

但我不认为第二行

 list.delete(y);

做你想做的事。它确实从列表中“删除”节点 y(如您所愿),但通过将数据从 y 之后的节点移动到 y 的位置并删除该节点来实现。所以现在 y.next 指向原始 y 之后的节点之后的节点。也许图表会有所帮助。

在 list.delete(y) 之前

 node:     ... - y - a - b - c - ... - z
 data:     ... - Y - A - B - C - ... - Z
                     ^ 
                     y.next points here (data is A)

list.delete(y)之后

 node:     ... - y - b - c - ... - z
 data:     ... - A - B - C - ... - Z
                     ^ 
                     y.next points here (data is B)
                 ^
                 y points here (data is A)

所以如果你在你的行中增加 y

 y:=y^.next;

在您的迭代循环中,您将错过测试数据 A。您可以通过删除 y:=y^.next; 来解决此问题。线。但是那行中的while循环仍然会有问题

 while y<>z do begin

因为指向节点 y 的指针不再改变(因为您删除了 y := y^.next),所以 y 永远不会等于 z。解决此问题的最简单(但可能不是最优雅)的方法可能是将行替换为

 while y^.next <>z do begin

并添加一个最终案例来测试最后一个节点。

然后主循环看起来像(未经测试):

 while y^.next <> z do begin
         if y^.data < x^.data then begin
                 list.insertInstead(x,y^.data);
                 list.delete(y);
         end;
 end;
 if y^.data < x^.data then begin
         list.insertInstead(x,y^.data);
         list.delete(y);
 end;

或者,通过定义一个新的过程

 procedure list.moveiflessthan(x,y : pnode);
 begin
      if y^.data < x^.data then begin
              list.insertInstead(x,y^.data);
              list.delete(y);
      end;
 end;

你得到

 while y^.next <> z do
         if y^.data < x^.data then 
                 list.moveiflessthan(x,y);
 if y^.data < x^.data then
         list.moveiflessthan(x,y);

如果您到达列表末尾(我尚未检查),可能仍然会出现最终错误,但我相信您可以解决这个问题...

【讨论】:

    猜你喜欢
    • 2021-06-28
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多