排序算法——堆排序

来源:互联网 发布:windows纯净版系统好吗 编辑:程序博客网 时间:2024/06/05 18:14

最大堆是这样一种结构:它的孩子节点的key都小于等于父节点;如果孩子节点的key都大于等于父节点,就称为最小堆。

堆排序(Heap Sort)就是利用堆进行排序的算法,它的基本思想是:

将待排序的序列构造成一个大顶堆(或小顶堆)。

此时,整个序列的最大值就是堆顶的根结点。将它移走(就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值)然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的大值。

如此反复执行,便能得到一个有序序列了。

 

堆排序的过程大致分为4大步:

1.利用原来的数组建立一个最大堆。此时,数组中最大的元素肯定是在data[0]中保存的。

2.把最大堆的data[0]与data[n-1]元素交换,此时最大的元素就跑到data[n-1]中了。3.忽略最后一个元素,调整整个堆,使得元素交换以后又是一个最大堆。

4.将最大堆的data[0]与data[n-2]进行交换,以此类推。

整个程序的难点在于:如何调整一个堆,让他变为最大堆。这个问题可以递归的解决:假设某个节点的左右子树已经是最大堆了,那么如需要将根节点与左右子树相比较,然后(如果需要的话)与左右子树中最大的交换;但是交换完以后,可能会引起左右子树中的一颗不再是最大,那么就对于以左(或者右)子树为根的子树继续重复前面的过程,直到遇见叶子节点(因为对每个子树进行调整的时候,需要先和根结点比较并交换,然后再向下进行调整交换,所以递归的终结条件就是遇到叶子节点)

 

堆排序是对选择排序进行改进的排序算法,堆排序算法的时间复杂度是O(nlogn)。

//堆排序//调整堆,使以index为根的子树成为最大堆  void headAdjust(pArrayList list,int index,int length){//左孩子int lchild=index*2+1;//右孩子int rchild=index*2+2;int largest;//最大的下标//找出最大值的下标,存放在largest中if(lchild<=length&&list->data[lchild]>list->data[index])largest=lchild;elselargest=index;if(rchild<=length&&list->data[rchild]>list->data[index])largest=rchild;//如果需要交换if(largest!=index){//交换int tmp=list->data[index];//根结点的值list->data[index]=list->data[largest];list->data[largest]=tmp;//交换之后,需要判断下一级的3个结点是否需要调整headAdjust(list,largest,length);}}/*利用数组初始化一个最大堆,就需要从最后一个叶子节点的父节点开始,依次调用上面的heapAdjust函数就行了:*///自底而上的调用headAdjust将数组变成一个最大堆void BuildMaxHeap(pArrayList list){//从最后一个父节点开始,直到树根for(int i=(list->length-2)/2;i>=0;--i){headAdjust(list,i,list->length);}}/*将最大堆的根与数组的最后一个元素交换,然后忽略最后一个元素,重新调整堆。然后取倒数第二个元素重复上述步骤:*///堆排序void heapSort(pArrayList list){BuildMaxHeap(list);printf("构成最大堆:");printArrayList(list);      int len = list->length-1;  for(int i=len;i>0;i--){int tem=list->data[0];list->data[0]=list->data[i];list->data[i]=temp;printf("交换以后:");printArrayList(list); //排好以后就该忽略最后一个元素,然后考虑前n-1个元素了          --len;          headAdjust(list,0, len);  }printf("最终结果:");printArrayList(list);}


原文链接:http://blog.csdn.net/thefutureisour/article/details/7938944

1 0
原创粉丝点击