【问题标题】:Trying to Quicksort a linked list in python试图在python中对链表进行快速排序
【发布时间】:2020-03-03 09:47:36
【问题描述】:

我的教授要求我对链表执行快速排序。因为所有的递归和链接对我来说仍然很新,所以它变得相当混乱。问题似乎与无意中被分配为无的东西有关 到目前为止,这是我的代码:

class Node:
    def __init__(self, d, n):
        self.data = d
        self.next = n


class LinkedList:

    def __init__(self):
        self.head = None
        self.length = 0

    def append(self, d):
        if self.head == None:      
            self.head = Node(d,None) 
        else:
            ptr = self.head
            while ptr.next != None:
                ptr = ptr.next
            ptr.next = Node(d,None)
        self.length += 1

    def merge(self,other):
        ptr = self.head
        while ptr.next != None:
            ptr = ptr.next
        ptr.next = other.head

    def removeVal(self, d):
        if self.head == None:
            return
        if self.head.data == d:
            self.head = self.head.next
            self.length -= 1
        else:
            ptr = self.head 
            while ptr.next != None:
                if ptr.next.data == d:
                    ptr.next = ptr.next.next
                    self.length -= 1
                    break
                ptr = ptr.next  

    def sort(self):
        if self.head!=None:
            pivot=self.head.data
            self.removeVal(pivot)
            smaller=LinkedList()
            other=LinkedList()
            ptr=self.head
            while ptr.next!=None:
                ptr=ptr.next
                if ptr.data<pivot:
                    smaller.append(ptr.data)
                else:
                    other.append(ptr.data)
            smaller.sort()
            other.sort()
            self=smaller
            self.append(pivot)
            self.merge(other)


ls = LinkedList()
ls.append(0)
ls.append(1)
ls.append(3)
ls.sort()

运行会出现以下错误

Traceback (most recent call last):
  File "main.py", line 71, in <module>
    ls.sort()
  File "main.py", line 58, in sort
    other.sort()
  File "main.py", line 51, in sort
    while ptr.next!=None:
AttributeError: 'NoneType' object has no attribute 'next'

任何帮助将不胜感激

【问题讨论】:

  • 您不会检查任何元素是否以更小或其他的形式结束。如果头部大于/小于所有其他元素,则每个元素都可能为空。
  • 问题代码在概念上类似于快速排序,但它不是快速排序,它会涉及节点交换。确保教授可以接受这种方法。

标签: python algorithm sorting linked-list quicksort


【解决方案1】:

您的 sort() 函数失败,因为当您进入 while 循环时,ptr 可以为 None。 起初这并不明显,因为您在开始时进行了检查

if self.head != None

但如果列表只有 1 个条目,则对 self.removeVal(pivot) 的调用会将您的头指针设置为 None。 请注意,这最终总是会在您的快速排序期间发生,因为您正在递归地分解您的列表。最终它必须是一个 1 元素列表,因此会失败。

当发生这种情况时,您会看到您发布的堆栈跟踪:

AttributeError: 'NoneType' object has no attribute 'next'

要解决此问题,您可以重写 while 循环以直接查看 ptr 而不是 ptr.next

         while ptr is not None:
                if ptr.data<pivot:
                    smaller.append(ptr.data)
                else:
                    other.append(ptr.data)
                ptr=ptr.next

我发现的另一个问题是你的作业:

self=smaller

这可能是合法的 Python 代码,但我觉得它非常危险。我把它改成

self.head = smaller.head

否则,您的示例会从列表中删除一个元素(尽管我没有追查到底是什么原因) 请注意,这并没有真正更新您的长度属性,但我不明白为什么需要它,它没有在任何地方使用。

关于效率的另一个注意事项:您在算法中做了很多附加操作,并且列表非常昂贵,即您实现它们的方式。这可能不是你在这里练习的重点。但是,当您通过迭代所有现有元素进行追加时,您正在扼杀快速排序的效率。添加一个元素会花费您 O(n),因此将列表拆分为较小的列表和其他列表已经花费了 O(n^2)。

对于(链接)列表,合并排序是一种更好的排序算法,它也像快速排序一样运行 O(n*log(n))。

【讨论】:

  • 非常感谢您清晰详细的回答。
【解决方案2】:

这是完整的代码

#finding the pivot elemet
def partition(itemlist,low,high):
pivot=itemlist[high]
i=low-1
for j in range(low,high):
    if itemlist[j]<pivot:
        i=i+1;
        itemlist[i],itemlist[j]=itemlist[j],itemlist[i]
itemlist[i+1],itemlist[high]=itemlist[high],itemlist[i+1]
return i+1
# generating the partition
def sort(itemlist,low,high):
    if low < high:
        partitonIndex=partition(itemlist,low,high)
        sort(itemlist,low,partitonIndex-1)
        sort(itemlist,partitonIndex+1,high)
# array to be sort
itemlist=[5,3,6,2,7,1,2,9]
print(itemlist);
sort(itemlist,0,len(itemlist)-1)
print(itemlist);

输出

[5, 3, 6, 2, 7, 1, 2, 9]
[1, 2, 2, 3, 5, 6, 7, 9]

【讨论】:

    【解决方案3】:

    仔细阅读您的错误代码。它说

    File "main.py", line 51, in sort
    while ptr.next!=None:
    AttributeError: 'NoneType' object has no attribute 'next'
    

    这是一个很好的指标,可以说明问题出在哪里。您正在从第 51 行访问一个空节点。将 While ptr.next !=None 更改为 While ptr != None 并且错误消失。您需要通过测试找出原因。

    【讨论】:

      【解决方案4】:

      如上所述,请确保问题中显示的方法可以作为快速排序接受。您可能会考虑创建 3 个列表,节点 枢轴,并且仅在 2 个节点列表上使用递归!= 枢轴。向列表添加尾部引用将加快追加操作。快速排序重新链接节点以重新排列它们而不是不断分配节点的示例代码。

      class Node(object):
      
          def __init__(self, data):
              self.data = data
              self.next=None
      
      class Linkedlist(object):
      
          def __init__(self):
              self.head = None
              self.tail = None
              self.length = 0
      
          def push_back(self, data):
              self.length += 1
              new = Node(data)
              if(self.tail is None):
                  self.head = self.tail = new
              else:
                  self.tail.next = new
                  self.tail = new
      
          def pop_front(self):
              if(self.head is None):
                  return self.head
              self.length -= 1
              data = self.head.data
              self.head = self.head.next
              return data
      
          def show(self, head, tail):
              arr = []
              if(head is None):
                  print(arr)
                  return
              while(True):
                  if(head.data is not None):
                      arr.append(head.data)
                  if(head is tail):
                      break
                  head = head.next
              print(arr)
      
          def quicksort(self,head,tail):
              if(head is tail):               # if single node return
                  return head,tail
                                              # using 3 dummy nodes for 3 lists
              hlt = Node(None)                # head, tail < pivot list
              tlt = hlt
              heq = Node(None)                # head, tail = pivot list
              teq = heq
              hgt = Node(None)                # head, tail > pivot list
              tgt = hgt
              pivot = head
              curr  = head
              end   = tail.next
              while(curr is not end):
                  if(curr.data < pivot.data):
                      tlt.next = curr
                      tlt = curr
                  elif(curr.data == pivot.data):
                      teq.next = curr
                      teq = curr
                  else:
                      tgt.next = curr
                      tgt = curr
                  curr = curr.next
              heq = heq.next                  # at least 1 node (should release node)
              if(hlt is tlt):                 # if none < pivot
                  hlt = heq                   #  (should release dummy node)
                  tlt = heq
              else:                           # else recurse on list < pivot
                  hlt = hlt.next              #  (should release dummy node)
                  hlt,tlt = self.quicksort(hlt,tlt)
                  tlt.next = heq
              if(hgt is tgt):                 # if none > pivot
                  hgt = teq                   #  (should release dummy node)
                  tgt = teq
              else:                           # else recurse on list > pivot
                  hgt = hgt.next              #  (should release dummy node)
                  hgt,tgt = self.quicksort(hgt,tgt)
                  teq.next = hgt
              return(hlt,tgt)
      
          def sort(self):
              if (self.head == None):         # if empty list return
                  return
              self.head,self.tail = self.quicksort(self.head,self.tail)
              self.tail.next = None
              return
      
      lists=Linkedlist()
      lists.push_back(27)
      lists.push_back(35)
      lists.push_back(23)
      lists.push_back(22)
      lists.push_back(38)
      lists.push_back(26)
      lists.push_back(31)
      lists.push_back(24)
      lists.push_back(37)
      lists.push_back(25)
      lists.push_back(33)
      lists.push_back(32)
      lists.push_back(28)
      lists.push_back(36)
      lists.push_back(21)
      lists.push_back(34)
      lists.sort()
      arr = []
      while(True):
          data = lists.pop_front()
          if(data is None):
              break
          arr.append(data)
      print(arr)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-06
        • 1970-01-01
        • 2011-07-10
        • 2012-03-11
        • 1970-01-01
        • 1970-01-01
        • 2022-11-13
        相关资源
        最近更新 更多