Xorkox
Xorkox

Reputation: 77

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]

Upvotes: 3

Views: 539

Answers (2)

Mehdi Yeganeh
Mehdi Yeganeh

Reputation: 2129

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

Upvotes: 1

FDinoff
FDinoff

Reputation: 31429

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.

Upvotes: 3

Related Questions