我在链接列表上使用合并排序时遇到了问题。我发现的问题是我的分区方法中的问题。
每当我分区并请求前半部分时,另一半结果就是前一个的相同。但如果我没有请求上半场,则下半场正确返回。以下是我的代码;
class ListNode:
def __init__(self, x, next = None):
self.val = x
self.next = next
def print_list(root):
while root:
print root.val,
root = root.next
print ''
def partition(root, is_first_half):
print_list(root)
if not root.next:
return root
slow_pointer, fast_pointer = root, root.next
while fast_pointer and fast_pointer.next != None:
fast_pointer = fast_pointer.next.next
slow_pointer = slow_pointer.next
if not is_first_half:
return slow_pointer
first_half, first_half_head, first_half_pointer = None, None, root
while first_half_pointer and first_half_pointer != slow_pointer:
if not first_half_head:
first_half = first_half_pointer
first_half_head = first_half
else:
first_half.next = first_half_pointer
first_half = first_half_pointer
first_half.next = None
first_half_pointer = first_half_pointer.next
return first_half_head
def merge(list1, list2):
new_list_head, new_list = None, None
if not list1:
return list2
if not list2:
return list1
while list1 and list2:
if list1.val < list2.val:
if not new_list_head:
new_list = list1
new_list_head = new_list
else:
new_list.next = list1
new_list = list1
new_list.next = None
list1 = list1.next
else:
if not new_list_head:
new_list = list2
new_list_head = new_list
else:
new_list.next = list2
new_list = list2
new_list.next = None
list2 = list2.next
if not list1:
while list2:
new_list.next = list2
new_list = list2
new_list.next = None
list2 = list2.next
return new_list_head
while list1:
new_list.next = list1
new_list = list1
new_list.next = None
list1 = list1.next
return new_list_head
def mergesort(root):
if not root.next:
return root
list1 = mergesort(partition(root, True))
list2 = mergesort(partition(root, False))
return merge(list1, list2)
if __name__ == '__main__':
a = ListNode(2, ListNode(4, ListNode(3, ListNode(1, ListNode(7)))))
print_list(a)
a = mergesort(a)
print_list(a)
答案 0 :(得分:1)
首先,在上半部分的代码中,为第二个元素调用
first_half = first_half_pointer
first_half.next = None
然后
first_half_pointer = first_half_pointer.next
所以first_half_pointer
变为None
并且循环结束,所以前半部分总是不超过两个元素。
其次,更重要的是,您可以通过以下行中断原始列表连接:
first_half.next = None
所以在partition(root, True)
之后,列表的后半部分会丢失。
答案 1 :(得分:1)
您的merge
方法似乎有一个错误,它会从列表中删除一堆元素。想想以下代码行中会发生什么:
new_list.next = None
您实际上正在删除列表的其余部分。在执行合并时,您似乎将保持整体中的最小元素,以及每个列表的最小元素,总共三个元素。尝试使用以下main
方法查看我的意思:
if __name__ == '__main__':
a = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5)))))
b = ListNode(6, ListNode(7, ListNode(8, ListNode(9, ListNode(10)))))
print_list(a)
print_list(b)
#a = mergesort(a)
c = merge(a, b)
print_list(c)
print_list(a)
print_list(b)
答案 2 :(得分:1)
您是否打算对分区进行破坏?也就是说,在运行分区后原始列表是否仍然存在及其所有值?你可以分道。
破坏性分区可能会快一些,因为它只需要取消一个节点的链接(尽管找到正确的节点是O(N)
)。要非破坏性地获取列表的前半部分,您需要复制它(为每个值创建新节点)。这也是O(N)
,但由于内存分配,可能会有更大的常数项。
这是一个快速的破坏性分区。它使用与您的代码不同的初始值,因此我们可以在slow_pointer
之后而不是在它之前直接拆分(这更难)。同时只获得破坏性分区的一半也没有意义,因为如果你请求前半部分后半部分将在之后无法访问,所以我们总是返回两半。
def partition(root):
fast_pointer = slow_pointer = ListNode(None, root) # new node "before the root"
while fast_pointer and fast_pointer.next:
fast_pointer = fast_pointer.next.next
slow_pointer = slow_pointer.next
mid = slow_pointer.next
slow_pointer.next = None # break one link in the list
return root, mid # return both halves of the list
这是一个非破坏性的替代版本。列表的后半部分是对原始相同节点的引用,但返回的前半部分是新节点中的副本
def partition_non_destructive(root):
root = fast_pointer = slow_pointer = ListNode(None, root) # root anchors the copy
while fast_pointer and fast_pointer.next:
fast_pointer = fast_pointer.next.next
slow_pointer.next = ListNode(slow_pointer.next.value, # copy the next node
slow_pointer.next.next)
slow_pointer = slow_pointer.next # slow_pointer is always the latest copied node
mid = slow_pointer.next
slow_pointer.next = None # unlink copied half from the rest
return root.next, mid # return both halves of the list
这两个函数都适用于任何长度的列表,包括长度为1(ListNode("foo")
)和零(None
)。对于奇数长度列表,返回的前半部分将始终大于后半部分。