前面两篇讲了排序中的交换类和插入类
今天我们来讲一下选择类中的选择排序和堆排序;
归并类的归并排序
选择排序
/**
* 选择排序
* 初始状态:无序区为R[1..n],有序区为空;
* 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。
* 该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,
* 使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
* n-1趟结束,数组有序化了。
* @param A
* @param n
* @return
*/
public int[] selectionSort(int[] A, int n) {
//简单选择排序算法,排序结果为递增数组
//记录最小下标值
int min=0;
//固定左边的数字
for(int i=0; i<A.length-1;i++){
min = i;
//找到下标i开始后面的最小值
for(int j=i+1;j<A.length;j++){
if(A[min]>A[j]){
min = j;
}
}
//确保稳定排序,数值相等就不用交换
if(i!=min){
swap(A,i,min);
}
}
return A;
}
堆排序
/**
* 堆排序
* 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
* 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
* 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,
* 然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。
* 不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
* @param array
* @return
*/
public int[] heapSort(int[] array){
int len = array.length;
//初始化堆,构造一个最大堆
for(int i = (len/2 - 1);i >= 0;i--){
heapAdjust(array,i,len);
}
//将堆顶的元素和最后一个元素交换,并重新调整堆
for(int i = len - 1;i > 0;i--){
int temp = array[i];
array[i] = array[0];
array[0] = temp;
heapAdjust(array,0,i);
}
return array;
}
/**
* 调整堆
* @param array
* @param index
* @param length
*/
public void heapAdjust(int[] array,int index,int length){
//保存当前结点的下标
int max = index;
//当前节点左子节点的下标
int lchild = 2*index;
//当前节点右子节点的下标
int rchild = 2*index + 1;
if(length > lchild && array[max] < array[lchild]){
max = lchild;
}
if(length > rchild && array[max] < array[rchild]){
max = rchild;
}
//若此节点比其左右孩子的值小,就将其和最大值交换,并调整堆
if(max != index){
int temp = array[index];
array[index] = array[max];
array[max] = temp;
heapAdjust(array,max,length);
}
}
/**
* 归并排序
* 把长度为n的输入序列分成两个长度为n/2的子序列;
* 对这两个子序列分别采用归并排序;
* 将两个排序好的子序列合并成一个最终的排序序列。
* @param A
* @param n
* @return
*/
public int[] mergeSort(int[] A, int n) {
//归并排序,递归做法,分而治之
mSort(A,0,n-1);
return A;
}
private void mSort(int[] A,int left,int right){
//分而治之,递归常用的思想,跳出递归的条件
if(left>=right){
return;
}
//中点
int mid = (left+right)/2;
//有点类似后序遍历!
mSort(A,left,mid);
mSort(A,mid+1,right);
merge(A,left,mid,right);
}
//将左右俩组的按序子序列排列成按序序列
private void merge(int[] A,int left,int mid,int rightEnd){
//充当tem数组的下标
int record = left;
//最后复制数组时使用
int record2 = left;
//右子序列的开始下标
int m =mid+1;
int[] tem = new int[A.length];
//只要left>mid或是m>rightEnd,就跳出循环
while(left<=mid&&m<=rightEnd){
if(A[left]<=A[m]){
tem[record++]=A[left++];
}else{
tem[record++]=A[m++];
}
}
while(left<=mid){
tem[record++]=A[left++];
}
while(m<=rightEnd){
tem[record++]=A[m++];
}
//复制数组
for( ;record2<=rightEnd;record2++){
A[record2] = tem[record2];
}
}