由于某种原因,我的Heapsort无法正常工作。使用以下测试程序:
int main()
{
AddArrayElement(10);
AddArrayElement(110);
AddArrayElement(20);
AddArrayElement(100);
AddArrayElement(30);
AddArrayElement(90);
AddArrayElement(40);
AddArrayElement(80);
AddArrayElement(50);
AddArrayElement(70);
AddArrayElement(60);
HeapSort();
PrintHeap();
system("pause");
return 0;
}
我得到以下输出:
堆有元素...... 110,100,80,70,90,40,10,50,30,60,20,
你看,数组没有被排序。
期望结果像10, 20, 30, ...., 110,
我验证了以下内容:
ShiftDown()
工作正常。Heapify()
工作正常。但是HeapSort()
函数无法对数组进行排序。
有人可以帮我找到这个bug吗?这是我的逻辑还是其他什么?
#include "Heap.h"
#include <stdio.h>
#include <math.h>
int array[SIZE] = {0};
int lastElementIndex = -1;
void PrintHeap()
{
int i=0;
printf("\n\n");
if(lastElementIndex >= 0)
{
printf("Heap has Elements...");
for(i=0 ; i<=lastElementIndex ; i++)
{
printf("%d, ", array[i]);
}
}
else
{
printf("Heap is Empty...");
}
printf("\n\n");
}
void Swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void SwapElements(int i, int j)
{
Swap(&array[i], &array[j]);
}
void SetRootElement(int element)
{
array[0] = element;
}
void DeleteRightMostElement()
{
array[lastElementIndex] = EMPTY;
--lastElementIndex;
}
void AddArrayElement(int element)
{
++lastElementIndex;
array[lastElementIndex] = element;
}
#pragma region HasXXX()
int HasAnyElement()
{
if(lastElementIndex > -1) return 1;
else return 0;
}
int HasLeftChild(int i)
{
int lastIndex = EMPTY;
if(HasAnyElement())
{
lastIndex = GetLastElementIndex();
if(lastIndex<=0 || lastIndex==i)
{
return 0;
}
else
{
if(2*i+1 <= GetLastElementIndex()) return 1;
else return 0;
}
}
else
{
return 0;
}
}
int HasRightChild(int i)
{
int leftChildIndex = EMPTY;
int rightChildIndex = EMPTY;
if(HasAnyElement())
{
if(HasLeftChild(i))
{
leftChildIndex = GetLeftChildIndex(i);
rightChildIndex = leftChildIndex + 1;
if(rightChildIndex <= GetLastElementIndex())
{
return 1;
}
else
{
if(2*i+2 <= GetLastElementIndex()) return 1;
else return 0;
}
}
else
{
return 0;
}
}
else
{
return 0;
}
}
int HasAnyChild(int i)
{
if(HasLeftChild(i) || HasRightChild(i)) return 1;
else return 0;
}
int HasBothChild(int i)
{
int hasLeftChild = HasLeftChild(i);
int hasRightChild = HasRightChild(i);
if(hasLeftChild && hasRightChild) return 1;
else return 0;
}
int HasParent(int i)
{
if(i>0) return 1;
else return 0;
}
#pragma endregion
#pragma region GetXXXIndex()
int GetElementsCount()
{
if(HasAnyElement()) return lastElementIndex + 1;
else return EMPTY;
}
int GetLastElementIndex()
{
if(HasAnyElement()) return lastElementIndex;
else return EMPTY;
}
int GetParentIndex(int i)
{
if(HasParent(i)) return (int)floor((i-1)/2);
else return EMPTY;
}
int GetLeftChildIndex(int i)
{
if(HasLeftChild(i)) return (2*i + 1);
else return EMPTY;
}
int GetRightChildIndex(int i)
{
if(HasRightChild(i)) return (2*i + 2);
else return EMPTY;
}
#pragma endregion
#pragma region GetXXXElement()
int GetRootElement()
{
return array[0];
}
int GetRightMostElement()
{
if(HasAnyElement()) return array[lastElementIndex];
else return EMPTY;
}
int GetElement(int i)
{
if(HasAnyElement()) return array[i];
else return EMPTY;
}
int GetParentElement(int i)
{
if(HasParent(i)) return array[GetParentIndex(i)];
else return EMPTY;
}
int GetLeftChildElement(int i)
{
if(HasLeftChild(i)) return array[GetLeftChildIndex(i)];
else return EMPTY;
}
int GetRightChildElement(int i)
{
if(HasRightChild(i)) return array[GetRightChildIndex(i)];
else return EMPTY;
}
#pragma endregion
#pragma region RemoveElementFromHeap()
void IterativeShiftDown(int i)
{
int leftOrRightChildIndex = EMPTY;
int currentIndex = i;
int currentElement = EMPTY;
int childElement = EMPTY;
while(HasAnyChild(currentIndex))
{
if(HasBothChild(currentIndex))
{
if(GetLeftChildElement(currentIndex) > GetRightChildElement(currentIndex))
{
leftOrRightChildIndex = GetLeftChildIndex(currentIndex);
}
else
{
leftOrRightChildIndex = GetRightChildIndex(currentIndex);
}
}
else if(HasLeftChild(currentIndex))
{
leftOrRightChildIndex = GetLeftChildIndex(currentIndex);
}
currentElement = GetElement(currentIndex);
childElement = GetElement(leftOrRightChildIndex);
if(currentElement < childElement)
{
SwapElements(currentIndex, leftOrRightChildIndex);
}
currentIndex = leftOrRightChildIndex;
}
}
void ShiftDownTheRootElement()
{
IterativeShiftDown(0);
}
#pragma endregion
void Heapify()
{
int i = 0;
int count = GetElementsCount();
int half = (count-2) / 2;
for(i=half ; i>=0 ; i--)
{
IterativeShiftDown(i);
}
}
void HeapSort()
{
int i = 0;
Heapify();
for (i=GetLastElementIndex() ; i>=0 ; i--)
{
SwapElements(i, 0);
IterativeShiftDown(i);
}
}
答案 0 :(得分:3)
我研究了代码并发现了一些错误。你正在创建堆,但在排序时你犯了一些错误:
在函数HeapSort中你在第i个元素上调用IterativeShiftDown而不是你需要在根元素上调用它以使它到达正确的位置。
此外,在将根元素移动到最后位置后,您不会更新堆的大小。您需要知道在堆排序中您正在进行的操作中,我们将数组的一部分作为堆,将其他部分作为已排序的部分。但是你没有减少堆的大小,所以堆超出堆扩展到已排序的区域,因此它再次选择更大的元素,这些元素在已排序的部分中,并导致再次形成堆。
用它替换你的HeapSort功能它将起作用:
void HeapSort()
{
int i = 0;
Heapify();
int size=GetLastElementIndex();
for (i=size ; i>=0 ; i--)
{
SwapElements(i, 0);
lastElementIndex--;
IterativeShiftDown(0); //shift the root down
}
lastElementIndex=size;
}