标签:
堆排序是对简单选择排序算法的一种改进。可以构建大顶堆(每个结点的值都大于等于其左右孩子的值)也可以构建小顶堆(每个结点的值都小于等于其左右孩子的值)。堆排自我感觉代码理解起来还是有点难,主要是如何构建一个新堆以及输出堆顶元素后,怎样调整剩余元素成为一个新堆。
1、堆排代码
1 void heapsort(SqList *s) 2 { 3 int increment = s->length/2; //父结点记录,父结点为从increment到s->length的记录 4 //构建大顶堆 5 for (int i = increment;i>0;i--) 6 { 7 heapadjust(s,i,s->length); 8 } 9 //交换大顶堆父结点到末端,将最大元素沉到叶结点处;再调整剩余元素为一个新的大顶堆 10 for(int j = s->length;j>1;j--) 11 { 12 swap(s,1,j); 13 heapadjust(s,1,j-1); 14 } 15 }
2、堆调整代码
1 void heapadjust(SqList *s,int i,int j) 2 { 3 //保存当前结点 4 int temp = s->data[i]; 5 int k; 6 //对该节点的左右孩子进行比较,再将左右孩子中较大的与根结点比较,将最大者作为根结点(与选择排序类似,选择最大的值作为根结点) 7 for (k = 2*i;k < j;k*=2) 8 { 9 if ((s->data[k]) < (s->data[k+1])) 10 { 11 k++; 12 } 13 if (temp > s->data[k]) 14 { 15 break; 16 } 17 s->data[i] = s->data[k]; 18 i = k; 19 } 20 s->data[i] = temp; 21 }
堆排测试完整代码:
1 #include <iostream> 2 using namespace std; 3 #define MAXSIZE 100 4 5 struct SqList 6 { 7 int data[MAXSIZE]; 8 int length; 9 }; 10 11 void heapadjust(SqList *s,int i,int j) 12 { 13 //保存当前结点 14 int temp = s->data[i]; 15 int k; 16 //对该节点的左右孩子进行比较,再将左右孩子中较大的与根结点比较,将最大者作为根结点(与选择排序类似,选择最大的值作为根结点) 17 for (k = 2*i;k < j;k*=2) 18 { 19 if ((s->data[k]) < (s->data[k+1])) 20 { 21 k++; 22 } 23 if (temp > s->data[k]) 24 { 25 break; 26 } 27 s->data[i] = s->data[k]; 28 i = k; 29 } 30 s->data[i] = temp; 31 } 32 33 void swap(SqList *s,int i,int j) 34 { 35 int temp; 36 if (s->data[i] > s->data[j]) 37 { 38 temp = s->data[i]; 39 s->data[i] = s->data[j]; 40 s->data[j] = temp; 41 } 42 } 43 44 void heapsort(SqList *s) 45 { 46 int increment = s->length/2; //父结点记录,父结点为从increment到s->length的记录 47 //构建大顶堆 48 for (int i = increment;i>0;i--) 49 { 50 heapadjust(s,i,s->length); 51 } 52 //交换大顶堆父结点到末端,将最大元素沉到叶结点处;再调整剩余元素为一个新的大顶堆 53 for(int j = s->length;j>1;j--) 54 { 55 swap(s,1,j); 56 heapadjust(s,1,j-1); 57 } 58 } 59 60 void main() 61 { 62 SqList s; 63 s.length = 5; 64 int m; 65 for (int i = 1; i <= s.length;i++) 66 { 67 cin >> m; 68 s.data[i] = m; 69 } 70 heapsort(&s); 71 for (int i = 1; i <= s.length;i++) 72 { 73 cout << s.data[i] << " "; 74 } 75 system("pause"); 76 }
结果:
复杂度分析:
堆排序的运行时间主要消耗在初始构建堆和重建堆时的反复筛选上。在构建堆的过程中,根结点与其左右孩子结点最多进行两次的比较与交换操作,因此整个构建堆的时间复杂度为O(n)。在正式排序的过程中,第i次取堆顶记录重建堆需要用O(logi)的时间(完全二叉树的性质),并需要取n-1次堆顶记录,因此,重建堆的时间复杂度为O(nlogn)。
空间复杂度上,它只有一个用来交换的暂存单元,空间复杂度为O(1)。
由于记录的比较与交换是跳跃式进行的,因此堆排是一种不稳定的排序算法。
标签:
原文地址:http://www.cnblogs.com/tracyhan/p/5475629.html