python - 对链表进行排序(交换节点)
问题描述
我正在尝试对包含此类节点的 LinkedList 进行排序:
class Node:
def __init__(self, data, next=None):
self.data, self.next = data, next
这个想法是获取一个序列(列表/元组/字符串),从中创建一个 LinkedList:
def __init__(self, seq):
self.front = self.Node(None)
node = self.front
for item in seq:
node.next = self.Node(item)
node = node.next
排序的逻辑是,在每次迭代中遍历链表,将每个项目与第一个项目进行比较,如果它更小/更大,则执行交换,继续遍历链表并执行相同的比较和操作。此处显示:
def min_sort(self, reverse):
self.count = 0
first = self.front
while first.next is not None:
print(self.get_list())
self.progress(first, reverse)
self.count += 1
first = first.next
def progress(self, first, reverse):
node = first
if (node is None): return
while True:
node = node.next
if node is None or node.next is None: break
if (reverse):
if (first.next.data < node.next.data):
self.vymen(first, node, node.next)
else:
if (first.next.data > node.next.data):
self.vymen(first, node, node.next)
问题在于交换本身(函数self.vymen(...)),它通常使用基本的数字链接列表,但是当加载一个字符串时,例如“我在Python中编码”,空格不会被交换到正确的位置使整个结果一团糟。交换本身是:
def vymen(self, first, prev, swap):
prevX, currX, prevY, currY = first, first.next, prev, swap
if (self.front.next.data == swap.data): return
if (currX is None or currY is None): return
if (currX != prevY):
if (prevX is not None): prevX.next = currY
else: self.front = currY
if (prevY is not None): prevY.next = currX
else: self.front = currX
temp = currX.next
currX.next = currY.next
currY.next = temp
else:
temp = currY.next
currX.next = temp
currY.next = currX
prevX.next = currY
正如我所看到的,它实际上只是空间的一个问题,我不明白问题是什么,因为它在开始时交换了第一个空间,而不是其余的。如果有人能够指出错误或告诉我发生了什么,我将不胜感激:)
解决方案
您的代码中有两个问题:
下面的语句
vymen
是麻烦的原因:if (self.front.next.data == swap.data): return
其目的是在交换节点的数据相等时避免不必要的交换。但是它不应该引用
self.front.next
,而是curX
- 因为那是要交换的节点:if currX.data == currY.data: return
if
紧随其后的条件此时没有用:if (currX is None or currY is None): return
...正如我们在这一点上已经提到的
swap.data
(即)。currY.data
因此,如果这确实可行,则应在引用currY.data
or之前对其进行检查currX.data
。所以把它和前面的结合起来if
:if currX is None or currY is None or currX.data == currY.data: return
当交换两个连续的(!)节点时,主循环
progress
将跳过一个节点。在这种情况下,在调用 之前,将变为将跳过。所以在调用之后,仍然会引用同一个节点,但它在列表中的位置更远。结果,有一个节点不会有循环的迭代。这是导致错误输出的原因,即使是纯数字也是如此。为了解决这个问题,您可以进行调整,使其返回与调用开始时处于相同位置的节点。然后调用者应该将该引用重新分配给它的变量。vymen
node
currX
node.next
node
vymen
node
node
其他一些评论:
在 Python 中,不需要在
if
条件周围加上括号在
vymen
中,以下条件应始终为真:if (prevX is not None): prevX.next = currY else: self.front = currY
这绝不应该是真的,因为您已经将链表设计为在其前面有一个哨兵节点(具有 value
None
)。所以你甚至不想self.front = currY
执行!prevX
永远不应该None
。它也绝不会None
以您调用此函数的方式出现。因此,只需删除此构造并分配:prevX.next = currY
紧随其后的也应该发生同样的情况
if..else
。不应该需要它的
vymen
最后一个参数 (swap
),因为它应该始终是 的值prev.next
。所以函数可以像这样开始:def vymen(self, first, prev): prevX, currX, prevY, currY = first, first.next, prev, prev.next
调用将是(还要注意返回值的分配):
node = self.vymen(first, node)
遗憾的是,在 的函数头之后,您定义了与and
vymen
完全相同的新变量:和。为什么不立即这样命名参数变量呢?first
prev
prevX
prevY
遗憾的是,在
progress
您的正文中,第一个语句是if
with a 。您可以更好地重写它,以便在语句中具有条件break
while True
while
综上所述,这是有问题的两种方法的结果代码:
def progress(self, first, reverse):
if first is None or first.next is None:
return
node = first.next
while node.next: # Use a condition to exit instead of break
if reverse:
if first.next.data < node.next.data:
# Take the return value, and pass one argument less
node = self.vymen(first, node)
else:
if first.next.data > node.next.data:
# Take the return value, and pass one argument less
node = self.vymen(first, node)
node = node.next
def vymen(self, prevX, prevY): # Use the desired variable names
# No need for the swap argument
currX, currY = prevX.next, prevY.next
# Corrected comparison of the two nodes' data, and put the
# conditions in the right order:
if currX is None or currY is None or currX.data == currY.data:
return prev # return the node at the position of prev
if currX != prevY:
# Make the following assignments unconditionally
prevX.next = currY
prevY.next = currX
temp = currX.next
currX.next = currY.next
currY.next = temp
# Return the reference of the node that is in the position
# of prev: it is still in the same position:
return prev
else:
temp = currY.next
currX.next = temp
currY.next = currX
prevX.next = currY
# Return the reference of the node that is in the position
# of prev: it has moved, so now it is...:
return currY
推荐阅读
- javascript - 根据计算出的数字显示不同的图像
- javascript - 使用 TinyMce 打开图像对话框时如何防止 Windows 资源管理器打开?
- tensorflow - 在 GradientTape(persistent=True) 之后调用 __exit_
- sed - sed 删除字符串直到下一次出现
- vue.js - Vue UI 未在新项目上启动
- javascript - 查找一定时间内的用户数量
- c# - 当文件明显应该存在时,为什么 JsonConfigurationSource 会抛出 FileNotFoundException?
- r - 特定多面体上的 R 密度图
- python - 能够使用 Visual Studio 2022 中的 AWS Toolkit 在 AWS Lambda 中部署 Python
- c++ - 在结构中创建具有 n 个元素的向量