7 堆排序
将数组根据下标看成二叉树,写代码的过程中二叉树节点从1开始,数组节点从0开始,然后就被反复的切换搞死了。。。 其实用二叉树节点从0开始标记,根为i时,左子树为2i+1,右子树为2i+2,从子树寻找根时,(i-1)/2也能找到,这样就不用2套下标了。。。
思路是首先生成大堆(根大于左子树和右子树),方法是一个循环A从最后一个根也就是下标为n/2的节点开始到第一个根(下标为0),分别与左右子树比较找到最大的数互换放在根的位置,如果交换发生就将原来的子树变为根,递归进入下一层比较,直到比较到输入的最后位置为止。如果交换没有发生说明下面都是堆,则break跳出来。
生成堆以后交换最大的元素到最后,最后的元素放在第一个,继续执行生成大堆 A 内的代码,所不同的是递归进入到最后比较的最后位置应该在刚刚与第一个元素交换的位置前面,这个过程执行n-1次则排序完成。复杂度为o(nlogn)
代码如下:
//堆排序
public void heapSort(T[] t,Comparator<T> c){
createHeap(t,t.length-1,c);//建立初堆
for(int i=t.length-1;i>0;i--){ //每次最后和第一个元素互换,将最大元素
T temp=t[i];t[i]=t[0];t[0]=temp; //沉底,第一个不需要所以for条件为>0
reconstruct(t,0,i-1,c); //数组从0~i-1重新构造堆
}
}
/**
* 数组下标从0开始,二叉树从1开始,注意转换
* @param t
* @param lastIndex 数组的最后一个索引下标
* @param c
*/
private void createHeap(T[] t,int lastIndex,Comparator<T> c){
for(int i=(lastIndex+1)/2;i>=1;i--)//i的值为二叉树的根下标,依次调整为堆
reconstruct(t,i-1,t.length-1,c);//传递的为数组下标
}
/**
*
* @param t
* @param firstIndex 数组第一个下标
* @param lastIndex 数组最后一个下标
* @param c
*/
private void reconstruct(T[] t,int firstIndex,int lastIndex,Comparator<T> c){
int first = firstIndex+1;//转化为二叉树
int last = lastIndex+1;// 的下标
int index = first*2;
while(index<=last){//左子树存在
if(index+1<=last&&c.compare(t[index], t[index-1])>0){//右子树存在且大
if(c.compare(t[first-1],t[index])<0){//右子树大于根
T temp=t[first-1];t[first-1]=t[index];t[index]=temp;
first = index+1;
index = 2*first;
}else{
break;
}
}else if(c.compare(t[first-1], t[index-1])<0){
T temp=t[first-1];t[first-1]=t[index-1];t[index-1]=temp;
first = index;
index = first*2;
}else{
break;
}
}
}
8 快速排序的变体(寻找第k小的元素)
这个第k小就是支点,其他与快速排序类似,还少了大量的递归
代码如下(这个代码其实是求Queue里面第size/2+1大小的元素,除了泛型和函数名,然后上面都是将比较当成函子塞入方法中,这里直接实现比较接口,这些是不同的,但算法一样):
//快速排序变体,分割点就是要求的中间元素
private E peekMedian(Object[] e,int head,int tail,int location){
int i = head;
int j = tail+1;
while(true){
while(((Comparable<E>) e[--j]).compareTo((E) e[head])>0)
;
while(((Comparable<E>) e[++i]).compareTo((E) e[head])<0)
;
if(i>j)
break;
Object temp=e[i];e[i]=e[j];e[j]=temp;
}
Object temp=e[head];e[head]=e[j];e[j]=temp;
if(j==location)
return (E)e[j];
else if(j<location)
return peekMedian(e,++j,tail,location);
else
return peekMedian(e,head,--j,location);
}
排序完整代码 :
各种排序算法(4)