堆实质上是满足如下性质的完全二叉树:树中任一非叶子结点的关键字均大于等于其孩子结点的关键字。例如序列10,15,56,25,30,70就是一个堆,它对应的完全二叉树如上图所示。这种堆中根结点(称为堆顶)的关键字最小,我们把它称为小根堆。反之,若完全二叉树中任一非叶子结点的关键字均大于等于其孩子的关键字,则称之为大根堆。
5.3. 排序过程:
堆排序正是利用小根堆(或大根堆)来选取当前无序区中关键字小(或最大)的记录实现排序的。我们不妨利用大根堆来排序。每一趟排序的基本操作是:将当前无序区调整为一个大根堆,选取关键字最大的堆顶记录,将它和无序区中的最后一个记录交换。这样,正好和直接选择排序相反,有序区是在原记录区的尾部形成并逐步向前扩大到整个记录区。
:对关键字序列42,13,91,23,24,16,05,88建堆。
5.4. 程序实现
/// summary/// 小根堆排序/// /summary/// param name="dblArray"/param/// param name="StartIndex"/param/// returns/returnsprivate static void HeapSort(ref double[] dblArray ){ for(int i = dblArray.Length -1 ; i = 0; i--) { if(2*i+1dblArray.Length) { int MinChildrenIndex = 2*i+1 ; //比较左子树和右子树,记录最小值的Index if(2*i+2 dblArray.Length ) { if(dblArray[2*i+1]dblArray[2*i+2]) MinChildrenIndex = 2*i+2; } if(dblArray[i] dblArray[MinChildrenIndex]) { ExchageValue(ref dblArray[i],ref dblArray[MinChildrenIndex]); NodeSort(ref dblArray ,MinChildrenIndex); } } }}/// summary/// 节点排序/// /summary/// param name="dblArray"/param/// param name="StartIndex"/paramprivate static void NodeSort(ref double[] dblArray,int StartIndex){ while(2*StartIndex+1 dblArray.Length) { int MinChildrenIndex = 2*StartIndex+1 ; if(2*StartIndex+2 dblArray.Length ) { if(dblArray[2*StartIndex+1]dblArray[2*StartIndex+2]) { MinChildrenIndex = 2*StartIndex+2; } } if(dblArray[StartIndex] dblArray[MinChildrenIndex]) { ExchageValue(ref dblArray[StartIndex],ref dblArray[MinChildrenIndex]); StartIndex = MinChildrenIndex ; } }}/// summary/// 交换值/// /summary/// param name="A"/param/// param name="B"/paramprivate static void ExchageValue(ref double A , ref double B){ double Temp = A ; A = B ; B = Temp ;}
总结:
人常说算法是程序的灵魂,在作项目的过程中时常注意且不可灵魂出窍。时常去回顾一下以前的数据重要性就如同基督徒每周要做礼拜一样。不能因为有了C# 和Java这种平台之后,就忽略了基础的重要性。
我用C#的控制台程序 把这几个算法实现了一下,代码在附件中,如有写的不好的地方,敬请指正。