各种排序算法(3)

7 堆排序

将数组根据下标看成二叉树,写代码的过程中二叉树节点从1开始,数组节点从0开始,然后就被反复的切换搞死了。。。 其实用二叉树节点从0开始标记,根为i时,左子树为2i+1,右子树为2i+2,从子树寻找根时,(i-1)/2也能找到,这样就不用2套下标了。。。

思路是首先生成大堆(根大于左子树和右子树),方法是一个循环A从最后一个根也就是下标为n/2的节点开始到第一个根(下标为0),分别与左右子树比较找到最大的数互换放在根的位置,如果交换发生就将原来的子树变为根,递归进入下一层比较,直到比较到输入的最后位置为止。如果交换没有发生说明下面都是堆,则break跳出来。  

生成堆以后交换最大的元素到最后,最后的元素放在第一个,继续执行生成大堆 A 内的代码,所不同的是递归进入到最后比较的最后位置应该在刚刚与第一个元素交换的位置前面,这个过程执行n-1次则排序完成。复杂度为o(nlogn)

代码如下:

  1. //堆排序  
  2.       
  3. <span style="font-size:14px;">  public void heapSort(T[] t,Comparator<T> c){  
  4.         createHeap(t,t.length-1,c);//建立初堆  
  5.         for(int i=t.length-1;i>0;i--){     //每次最后和第一个元素互换,将最大元素  
  6.             T temp=t[i];t[i]=t[0];t[0]=temp; //沉底,第一个不需要所以for条件为>0  
  7.             reconstruct(t,0,i-1,c); //数组从0~i-1重新构造堆  
  8.         }  
  9.     }  
  10.       
  11.     /** 
  12.      * 数组下标从0开始,二叉树从1开始,注意转换 
  13.      * @param t 
  14.      * @param lastIndex 数组的最后一个索引下标 
  15.      * @param c 
  16.      */  
  17.     private void createHeap(T[] t,int lastIndex,Comparator<T> c){  
  18.         for(int i=(lastIndex+1)/2;i>=1;i--)//i的值为二叉树的根下标,依次调整为堆  
  19.             reconstruct(t,i-1,t.length-1,c);//传递的为数组下标  
  20.     }  
  21.     /** 
  22.      *  
  23.      * @param t 
  24.      * @param firstIndex  数组第一个下标 
  25.      * @param lastIndex   数组最后一个下标 
  26.      * @param c 
  27.      */  
  28.     private void reconstruct(T[] t,int firstIndex,int lastIndex,Comparator<T> c){  
  29.         int first = firstIndex+1;//转化为二叉树  
  30.         int last = lastIndex+1;//         的下标  
  31.         int index = first*2;  
  32.         while(index<=last){//左子树存在  
  33.             if(index+1<=last&&c.compare(t[index], t[index-1])>0){//右子树存在且大  
  34.                 if(c.compare(t[first-1],t[index])<0){//右子树大于根  
  35.                     T temp=t[first-1];t[first-1]=t[index];t[index]=temp;  
  36.                     first = index+1;  
  37.                     index = 2*first;  
  38.                 }else{  
  39.                     break;  
  40.                 }  
  41.             }else if(c.compare(t[first-1], t[index-1])<0){  
  42.                 T temp=t[first-1];t[first-1]=t[index-1];t[index-1]=temp;  
  43.                 first = index;  
  44.                 index = first*2;  
  45.             }else{  
  46.                 break;  
  47.             }  
  48.         }  
  49.     }</span>  

8 快速排序的变体(寻找第k小的元素)

这个第k小就是支点,其他与快速排序类似,还少了大量的递归

代码如下(这个代码其实是求Queue里面第size/2+1大小的元素,除了泛型和函数名,然后上面都是将比较当成函子塞入方法中,这里直接实现比较接口,这些是不同的,但算法一样):

  1. <span style="font-size:14px;">//快速排序变体,分割点就是要求的中间元素  
  2.     private E peekMedian(Object[] e,int head,int tail,int location){  
  3.             int i = head;  
  4.             int j = tail+1;  
  5.             while(true){  
  6.                 while(((Comparable<E>) e[--j]).compareTo((E) e[head])>0)  
  7.                     ;  
  8.                 while(((Comparable<E>) e[++i]).compareTo((E) e[head])<0)  
  9.                     ;  
  10.                 if(i>j)  
  11.                     break;  
  12.                 Object temp=e[i];e[i]=e[j];e[j]=temp;  
  13.             }  
  14.             Object temp=e[head];e[head]=e[j];e[j]=temp;  
  15.               
  16.             if(j==location)  
  17.                 return (E)e[j];  
  18.             else if(j<location)  
  19.                 return peekMedian(e,++j,tail,location);  
  20.             else  
  21.                 return peekMedian(e,head,--j,location);  
  22.               
  23.           
  24.     }</span>  
排序完整代码 : 各种排序算法(4)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值