如何就地实现堆排序?

你好世界

我当前的实现(如下所示)有效,但还没有到位。我试图谷歌,但我找不到一个例子。感谢您的指导!

如您所见,在排序的第二阶段,我使用了对原始列表进行切片,以便我可以对这个切片进行 heapify。但是,我不应该使用切片操作,因为它会创建一个新列表。我还能尝试什么?

```
from queue import Empty

# logic is easy but hard to achieve in-order.

class PriorityQueueBase():
    class _Item():
        __slots__ = "_key","_value"
        def __init__(self, k,v):
            self._key = k
            self._value = v
        def __lt__(self,other):
            return self._key < other._key
        def __str__(self):
            return str(self._key) +" "+ str(self._value)
    def is_empty(self):
        return len(self) == 0
class HeapPriorityQueue(PriorityQueueBase):
    # This is a maximum-oriented heap priority queue
    # This uses bottom-up construction method.
    def _parent(self,j):
        return (j-1) // 2
    def _left(self,j):
        return 2*j+1
    def _right(self,j):
        return 2*j+2
    def _has_left(self,j):
        return self._left(j) < len(self._data)
    def _has_right(self,j):
        return self._right(j) < len(self._data)
    def _swap(self,i,j):
        self._data[i],self._data[j] = self._data[j],self._data[i]
    def _upheap(self,j):
        parent = self._parent(j)
        if j>0 and self._data[j] > self._data[parent]:
            self._swap(j,parent)
            self._upheap(parent)
    def _downheap(self,j):
        if self._has_left(j) and self._has_right(j):
            left = self._data[self._left(j)]
            right = self._data[self._right(j)]
            if left > right:
                if self._data[self._left(j)] > self._data[j]:
                    self._swap(j,self._left(j))
                    self._downheap(self._left(j))
            else:
                if self._data[self._right(j)] > self._data[j]:
                    self._swap(j,self._right(j))
                    self._downheap(self._right(j))
        elif self._has_left(j):
            if self._data[self._left(j)] > self._data[j]:
                self._swap(j,self._left(j))
                self._downheap(self._left(j))
        
        # ---------------------public methods----------------------
    def __init__(self,contents=[]):
        if isinstance(contents[0],self._Item):
            self._data = contents
            print("the slice passed in",self)
        else:
            self._data = [self._Item(k,v) for k,v in contents]
        if len(self._data) > 1:
            self._heapify()
            print("after heapifying the slice",self)
    def __len__(self):
        return len(self._data)
    def add(self,key,value):
        i = self._Item(key,value)
        self._data.append(i)
        self._upheap(len(self._data)-1)
    def max(self):
        if self.is_empty():
            raise Empty("Priority queue is empty")
        item = self._data[0]
        return (item._key,item._value)
    def remove_max(self):
        if self.is_empty():
            raise Empty("Priority queue is empty")
        self._swap(0,len(self)-1)
        item = self._data.pop()
        self._downheap(0)
        return (item._key,item._value)
    def _heapify(self):
        start = self._parent(len(self._data)-1)
        for i in range(start,-1,-1):
            self._downheap(i)
    def __iter__(self):
        for i in self._data:
            yield i
    def __str__(self):
        l = [str(i)for i in self._data]
        return " ".join(l)

    def sort(self):
        l = len(self._data)
        for i in range(1,l):
            self._swap(0,l-i)
            print(self)
            # here it's not in-place. 
            slice = self._data[0:l-i]
            h = HeapPriorityQueue(slice)
            l1 = len(h._data)
            self._data[0:l-i]=h._data
            print(self)
        return self._data

c = ((1,"Frank"),(2,"Daniel"),(3,"Mark"),(4,"Mark"),(5,"Mark"),(6,"Mark"))
h = HeapPriorityQueue(c)
s = h.sort()
for i in s:
    print(i)
```
特里科特

您可以采取以下步骤使其就位:

  • 使堆可以只作用于给定列表的一部分,忽略不属于这部分的值。为此,引入一个size属性,该属性以与 相同的值开始len(contents),但可以由堆的用户减少。这意味着您还需要:

    • 替换每次使用len(self), 或len(self._data)self.size
    • is_empty方法移动到子类中,这实际上完全不需要子类。
  • 将创建堆的新实例的部分替换为:

    self.size -= 1
    self._downheap(0)
    
    • 因此,您不再需要构造函数中的以下部分:

      if isinstance(contents[0],self._Item):
          self._data = contents
          print("the slice passed in",self)
      

更新代码:

from queue import Empty

class HeapPriorityQueue():  # Subclassing removed
    class _Item():
        __slots__ = "_key","_value"
        def __init__(self, k,v):
            self._key = k
            self._value = v
        
        def __lt__(self,other):
            return self._key < other._key
        
        def __str__(self):
            return str(self._key) +" "+ str(self._value)
    
    def is_empty(self):
        return self.size == 0  # use self.size
        
    def _parent(self,j):
        return (j-1) // 2
        
    def _left(self,j):
        return 2*j+1
        
    def _right(self,j):
        return 2*j+2
        
    def _has_left(self,j):
        return self._left(j) < self.size  # use self.size
        
    def _has_right(self,j):
        return self._right(j) < self.size  # use self.size
        
    def _swap(self,i,j):
        self._data[i],self._data[j] = self._data[j],self._data[i]
        
    def _upheap(self,j):
        parent = self._parent(j)
        if j>0 and self._data[j] > self._data[parent]:
            self._swap(j,parent)
            self._upheap(parent)
            
    def _downheap(self,j):
        if self._has_left(j) and self._has_right(j):
            left = self._data[self._left(j)]
            right = self._data[self._right(j)]
            if left > right:
                if self._data[self._left(j)] > self._data[j]:
                    self._swap(j,self._left(j))
                    self._downheap(self._left(j))
            else:
                if self._data[self._right(j)] > self._data[j]:
                    self._swap(j,self._right(j))
                    self._downheap(self._right(j))
        elif self._has_left(j):
            if self._data[self._left(j)] > self._data[j]:
                self._swap(j,self._left(j))
                self._downheap(self._left(j))
        
    # ---------------------public methods----------------------
    def __init__(self,contents=[]):
        self.size = len(contents)
        # Removed support for _Item instances in contents
        self._data = [self._Item(k,v) for k,v in contents]
        if len(self._data) > 1:
            self._heapify()
            print("after heapifying the slice",self)
            
    def __len__(self):
        return len(self._data)
        
    def add(self,key,value):
        i = self._Item(key,value)
        self._data.append(i)
        self._upheap(self.size-1)   # use self.size
        
    def max(self):
        if self.is_empty():
            raise Empty("Priority queue is empty")
        item = self._data[0]
        return (item._key,item._value)
        
    def remove_max(self):
        if self.is_empty():
            raise Empty("Priority queue is empty")
        self._swap(0,self.size-1)  # use self.size
        item = self._data.pop()
        self._downheap(0)
        return (item._key,item._value)
        
    def _heapify(self):
        start = self._parent(self.size-1)  # use self.size
        for i in range(start,-1,-1):
            self._downheap(i)
            
    def __iter__(self):  # Warning: Does not take size into account
        for i in self._data:
            yield i
            
    def __str__(self):  # Warning: Does not take size into account
        l = [str(i) for i in self._data]
        return " ".join(l)

    def sort(self):
        l = len(self._data)
        for i in range(1,l):
            self._swap(0,l-i)
            print(self)
            # now it's in-place. 
            self.size -= 1
            self._downheap(0)
            print(self)
        return self._data


c = ((6,"Iris"), (3,"Helen"),(1,"Frank"),(4,"Joy"),(2,"Daniel"),(5,"Mark"))
h = HeapPriorityQueue(c)
s = h.sort()
for i in s:
    print(i)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章