简体   繁体   中英

Why doesn't my heapsort work?

i have this python Heapsort-Code made from a pseudocode from the net.

But it gives the wrong result.

def heapSortUp(a):          
    heapifyUp(a, len(a))

    end = len(a)-1
    while end > 0:
        a[end], a[0] = a[0], a[end]
        end -= 1
        siftUp(a, 0, end)
    return a

def heapifyUp(a, count):
    end = 1

    while end < count:
        siftUp(a, 0, end)
        end += 1

def siftUp(a, start, end):
    child = end

    while child > start:
        parent = int(math.floor((child-1)/2))       # floor = abrunden

        if a[parent] < a[child]:
            a[parent], a[child] = a[child], a[parent]
            child = parent
        else:
            return

I especially want to use the siftUP version.

by computing print heapSortUp([1,5,4,2,9,8,7]) it returns: [8, 7, 9, 2, 1, 4, 5, 7, 5]

The problem is that you need to sift down not up in heapSortUp(a)

def heapSortUp(a):          
    heapifyUp(a, len(a))

    end = len(a)-1
    while end > 0:
        a[end], a[0] = a[0], a[end]
        end -= 1
        siftDown(a, 0, end)
    return a

The reason you need to sift down is because sifting up invalidates the heap. This can be shown with a simple example.

Take a heap 4,3,2,1 . After one iteration of the sort you will have placed 4 at the end and 1 at the front. So the heap looks like this as a tree

 1
3 2

However when you sift up you swap the 1 and 2 . This implies that 2 has greater priority than 3. If you continue doing the sort (as it is written) you will up the array 1,3,2,4

To get the actual sort you needed to sift down the one so that the heap looked like after the first iteration.

 3
1 2

I leave the siftDown implementation to you.

For Ascending heap sort you can use this code:

def heapSort(a):
    count = len(a)
    heapify(a, count)

    end = count-1
    while end > 0:
        a[end], a[0] = a[0], a[end]
        end = end - 1
        siftDown(a, 0, end)


def heapify(a, count):
    start = math.floor((count - 1) / 2)

    while start >= 0:
        siftDown(a, start, count-1)
        start = start - 1

def siftDown(a, start, end):
    root = start

    while root * 2 + 1 <= end:
        child = root * 2 + 1
        swap = root
        if a[swap] < a[child]:
            swap = child
        if child+1 <= end and a[swap] < a[child+1]:
            swap = child + 1
        if swap != root:
            a[root], a[swap] = a[swap], a[root]
            root = swap
        else:
            return

Or you can use this code:

def heapSortDown(lst):
  for start in range(math.floor((len(lst)-2)/2), -1, -1):
    sift(lst, start, len(lst)-1)

  for end in range(len(lst)-1, 0, -1):
    lst[end], lst[0] = lst[0], lst[end]
    sift(lst, 0, end - 1)
  return lst

def sift(lst, start, end):
  root = start
  while True:
    child = root * 2 + 1
    if child > end: break
    if child + 1 <= end and lst[child] < lst[child + 1]:
      child += 1
    if lst[root] < lst[child]:
      lst[root], lst[child] = lst[child], lst[root]
      root = child
    else:
      break

and For Decending:

def heapSortDown(lst):
  for start in range(math.floor((len(lst)-2)/2), -1, -1):
    sift(lst, start, len(lst)-1)

  for end in range(len(lst)-1, 0, -1):
    lst[end], lst[0] = lst[0], lst[end]
    sift(lst, 0, end - 1)
  return lst

def sift(lst, start, end):
  root = start
  while True:
    child = root * 2 + 1
    if child > end: break
    if child + 1 <= end and lst[child] > lst[child + 1]:
      child += 1
    if lst[root] > lst[child]:
      lst[root], lst[child] = lst[child], lst[root]
      root = child
    else:
      break

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM