java实现常用的排序算法。
相应的思路再注释中。
class Sort{
//排序算法总结
/*
* 1.直接插入排序
* 序列中前n个数为已排序序列,将第n+1个数插入到前n个数的适当位置中。
*/
public int[] insertSort(int[] arr){
int insertNum;
//n个数的序列进行n-1次插入。
for(int i=1; i<arr.length; i++){
insertNum = arr[i];
//前i-1个数已经排好序,则将用第i个数和第j=i-1个数比较。如果大于第j个数,则将第j个数后移1位。
//并将待排序的数插入第j位。之后开始和第j-1位比较,循环比较到第一位。
for(int j=i-1; j>=0 && insertNum < arr[j]; j--){
arr[j+1] = arr[j];
arr[j] = insertNum;
}
}
return arr;
}
/*
* 2.希尔排序
* 先将序列按增量d分为若干子序列,然后对子序列使用直接插入排序。
* 然后减小增量d再进行一次直接插入排序。
* 直至d=0进行一趟直接插入排序
*/
public int[] shellSort(int[] arr){
int d = arr.length;
while(d != 0){
//对增量循环,对折增量
d = d/2;
for(int i=0; i<d; i++){
//d的大小就相当与子序列的组数。循环d,可认为是在循环组数
for(int j=i+d; j<arr.length; j+=d){
//从这里开始,就是对每一组开始进行直接插入排序。
//代码没区别,只是循环增量,还有在循环的起始位置上都要加上d。
//同时,最外层循环从每组第一个元素开始。那就是组数i加上增组数d
int s;
int insertNum = arr[j];
for(s=j-d; s>=0 && arr[s]>insertNum; s-=d){
arr[s+d] = arr[s];
arr[s] = insertNum;
}
}
}
}
return arr;
}
/*
* 3.简单选择排序
* 遍历整个序列将最小的数放到第一个。
* 遍历剩下的序列,将最小的放在最前面
* 重复上述步骤
*/
public int[] selectSort(int[] array){
for(int times=array.length-1; times>0; times--){
for(int idx=0; idx<times; idx++){
if(array[idx]>array[times]){
int tmp = array[times];
array[times] = array[idx];
array[idx] = tmp;
}
}
}
return array;
}
/*
* 4.堆排序
* 堆顶元素为最大值(大根堆)将堆顶元素输出,之后用堆中最后一个元素代替堆顶
* 再对堆进行筛选排序。调整过后输出新的堆顶重复上述步骤。(代码回头补吧)
*/
public int[] heapSort(int[] arr){
//一下这步操作,堆的构建就已经完成。
for(int i=arr.length-1; i>=0; i--){
percDown(arr, i, arr.length-1);
}
print("【构建堆已完成】 构建结果:");
printArr(arr);
//构建堆完成后,我们将堆顶元素放置到末尾,并将堆尾放到队首并重新构建堆
for(int j=arr.length-1; j>0; j--){
print("====================in=====================\n");
//交换堆顶和堆尾元素
//print("【此时的堆顶为:"+arr[0]+" 此时的堆尾为:"+arr[j]+"】\n");
int temp = arr[0];
arr[0] = arr[j];
arr[j] = temp;
print("【交换堆顶和堆尾元素后数组为:】");
printArr(arr);
//刨除堆尾元素重新构建堆
percDown(arr, 0, j-1);
print("【重新构建后数组为:】");
printArr(arr);
}
print("最终结果!!=》");
return arr;
}
/*
* 下滤操作:先比较根节点的孩子,选出较小的节点,之后将根节点和其比较
* 根节点小则交换
* @param arr=>需要被构建堆的数组
* @param node=>开始下滤的根节点
* @param len=>下滤树的大小
*/
public void percDown(int[] arr, int node, int len){
print("数组长度为:"+len+"\n");
int elem = arr[node];
while(node<len && 2*node+1<len){
int child = node*2+1;
print("当前根节点为:"+node+"\n 左孩子节点为:"+child+"\n");
if(child != len && arr[child+1] < arr[child]){
child++;
print("右孩子节点"+child+"值更小\n");
}
if(arr[child]<elem){
arr[node]=arr[child];
}else
//此处的break很有意思。意味着当根节点不比子节点大时,就需要跳出循环
//否则空穴会跳到下一个语句则循环外的赋值就出问题了。
break;
node = child;
}
arr[node]=elem;
}
/*
* 5.冒泡排序
* 两个元素两两比较,将大元素向下沉,小元素向上浮
*/
public int[] bubbleSort(int[] arr){
for(int i=0; i<arr.length; i++){
/*
* 下面的循环当中是两两比较的过程,并把大元素不断往后放。
* 因为是元素一个一个向后移,所以上一轮比较的大值又参与下一轮比较,
* 这样在一轮循环的最后就是序列中的最大值。
* 已经得到了整个序列中的最大值,所以最后以为就不需要比较了。
* 因此,内循环的边界条件需要用数组长度减去i(已经循环的次数,循环了几次就有几个最大值,也就是已经排好序的个数)
*/
for(int j=0; j<arr.length-1-i; j++){
if(arr[j]>arr[j+1]){
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
printArr(arr);
}
return arr;
}
/*
* 6.快速排序
*/
//快速排序入口
public int[] quickSort(int[] arr){
QKSort(arr, 0, arr.length-1);
return arr;
}
//快速排序过程
public void QKSort(int[] arr, int head, int tail){
if(head<tail){
//调用一趟排序过程。之后返回
int position = quickSortOne(arr, head, tail);
QKSort(arr, head, position-1);
QKSort(arr, position+1, tail);
}
}
//此函数为快速排序的一趟排序过程
public int quickSortOne(int[] arr, int head, int tail){
int base = arr[head];
/*
* 这里选最低位为基准数。那么循环中,就要让高位先往左走,在让低位往右走。
* 因为低位为基准数。则base存储了低位变量,而如果低位先往右走,但高位上目前没有空位则不方便交换
* 否则还要添加变量。当退出循环时,head=tail。便将base值放入其中。
*/
while(head<tail){
while(head<tail && arr[tail]>base)
tail--;
if(head<tail){
arr[head]=arr[tail];
head++;
}
while(head<tail && arr[head]<base)
head++;
if(head<tail){
arr[tail]=arr[head];
tail--;
}
}
arr[head]=base;
print("quick sort");
printArr(arr);
return head;
}
/*
* 7.归并排序
*/
//归并排序入口
public int[] mergeSort(int[] arr){
int[] temp = new int[arr.length];
mergeSort(arr, temp, 0, arr.length-1);
return arr;
}
public void mergeSort(int[] arr, int [] temp, int left, int right){
if(left < right){
//这里开始将排序问题递归分解。
int center = (left+right)/2;
mergeSort(arr, temp, left, center);
mergeSort(arr, temp, center+1, right);
//这里调用归并函数开始合并。
merge(arr, temp, left, center+1, right);
}
if(left == right)
merge(arr, temp, left, left, left);
}
public void merge(int[] arr, int[] temp, int leftStart, int rightStart, int rightEnd){
print("============================================");
print("beginArr = ");
printArr(arr);
int leftEnd = rightStart-1;
int tempArrPos = leftStart;
int numElems = rightEnd-leftStart+1;
print("leftStart = "+leftStart+" leftEnd = "+leftEnd+" rightStart = "+rightStart+" rightEnd = "+rightEnd+"\n");
//主循环,合并元素
while(leftStart<=leftEnd && rightStart <= rightEnd){
print("in main \n");
if(arr[leftStart] < arr[rightStart]){
print("left in \n");
temp[tempArrPos++] = arr[leftStart++];
}else{
temp[tempArrPos++] = arr[rightStart++];
print("right in \n");
}
}
//跳出上面的循环意味着,两个序列中有一个已经全部排好序。只需将剩下的序列依次填充就好
while(leftStart<=leftEnd){
temp[tempArrPos++] = arr[leftStart++];
print("in single left \n");
}
while(rightStart <= rightEnd){
temp[tempArrPos++] = arr[rightStart++];
print("in single right \n");
}
print("tempArr = ");
printArr(temp);
//将排好序的数组赋值给原数组
//temp的长度要比arr小,所以从后往前赋值防止越界
for(int i=0; i<numElems; i++, rightEnd--){
arr[rightEnd] = temp[rightEnd];
}
print("resArr = ");
printArr(arr);
}
public static void main(String[] args){
Sort s = new Sort();
int[] val = {43,32,23,13,5,8,14};
int[] ret = s.heapSort(val);
printArr(ret);
}
public static void print(Object o){
System.out.print(o);
}
public static void printArr(int[] arr){
String str = "[";
for(int i=0; i<arr.length; i++){
str += arr[i]+",";
}
str = str.substring(0, str.length()-1);
print(str+"]");
System.out.println();
}
}