排序算法的比较

1.冒泡排序
(1)算法原理:将第一个元素和第二个元素比较,若前者大于后者,则交换两者的位置,再将第二个元素与第三个元素比较,若前者大于后者则交换两者位置,以此类推直到倒数第二个元素与最后一个元素比较,若前者大于后者,则交换两者位置。这样一轮比较下来将会把序列中最大的元素移至序列末尾,这样就安排好了最大数的位置,接下来只需对剩下的(n-1)个元素,重复上述操作即可。
(2)算法:
public static int[] myBubbleSort(int[] arr){
for (int i = 0;i < arr.length-1;i++){
for (int j = 0;j < arr.length-1-i;j++){
if (arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1]= temp;
}
}
}
return arr;
}
(3)优化:
public static int[] myOptimizeBubbleSort(int[] arr){
boolean flag;
for (int i = 0;i < arr.length-1;i++){
flag = false;
for (int j = 0;j < arr.length-i-1;j++){
if (arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = true;
}
}
if (flag==false){
break;
}
}
return arr;
}
2.快速排序
(1)算法原理
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4)重复上述过程,可以看出这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
(2)算法实现
public class QuickSort {
/**
* 快速排序
*/
public static int[] myQuickSort(int[] arr){
quickSortProcess(arr,0,arr.length-1);
return arr;
}

/**
 * 快速排序的过程
 * @param arr
 * @param lowIndex 
 * @param highIndex
 */
public static void quickSortProcess(int[] arr,int lowIndex,int highIndex){
    //区间长度
    int size = highIndex-lowIndex+1;
    if (size<=1){
        return;
    }
    //找到中间下标
    int keyIndex = partition(arr,lowIndex,highIndex);
    //对左边区间进行快速排序
    quickSortProcess(arr,lowIndex,keyIndex-1);
    //对右边区间进行快速排序
    quickSortProcess(arr,keyIndex+1,highIndex);
}

/**
 * 进行分组
 * @param arr
 * @param lowIndex 起始下标
 * @param highIndex 终止下标
 * @return 找到的关键值的下标
 */
private static int partition(int[] arr, int lowIndex, int highIndex) {
    int leftIndex = lowIndex;
    int rightIndex = highIndex;
    //找一个分解值
    int key = arr[lowIndex];
    //进行区分
    while (leftIndex<rightIndex){
        //找到右边小于关键值的下标
        while (leftIndex<rightIndex && arr[rightIndex]>=key){
            rightIndex--;
        }
        //左边大于关键值的下标
        while (leftIndex<rightIndex && arr[leftIndex]<=key){
            leftIndex++;
        }
        //交换
        swap(arr,leftIndex,rightIndex);
    }
    //交换关键值,即key和leftIndex(此时leftIndex和righIndex重合)
    swap(arr,leftIndex,lowIndex);
    return leftIndex;
}

/**
 * 交换
 * @param arr
 * @param index1
 * @param index2
 */
    public static void swap(int[] arr,int index1,int index2){
    int temp = arr[index1];
    arr[index1] = arr[index2];
    arr[index2] = temp;
}

public static void main(String[] args) {
    int[] arr = {3,4,9,8,6,3,4};
    myQuickSort(arr);
    for (int i = 0 ;i < arr.length;i++){
        System.out.print(arr[i]+" ");
    }
}

}
3.归并排序
(1)算法思想
一般用于对总体无序,但是各子项相对有序的数列
将两个顺序序列合并成一个顺序序列的方法。
把数组平均分成两份。分别对左右两个区间进行相同的处理,知道区间内个数(size=0/1)
合并左右两个有序数组。
(2)算法实现
public class MergeSort {
public static int[] myMergeSort(int[] arr){
mergeSortPart(arr,0,arr.length);
return arr;
}

/**
 * 分区间
 * @param arr
 * @param lowIndex
 * @param highIndex
 */
private static void mergeSortPart(int[] arr, int lowIndex, int highIndex) {
    //区间是左闭右开的
    int size = highIndex-lowIndex;
    if (size<=1){
        return;
    }
    //找到中间下表,把整个数组平均分成两个区间
    int midIndex = (highIndex+lowIndex)/2;
    mergeSortPart(arr,lowIndex,midIndex);
    mergeSortPart(arr,midIndex,highIndex);

    //合并两个有序区间
    mergeSortProcess(arr,lowIndex,midIndex,highIndex);
}

/**
 * 合并两个有序区间
 * @param arr 数组
 * @param lowIndex 左区间左下标
 * @param midIndex 左区间右下标,右区间左下标
 * @param highIndex 右区间右下标
 */
private static void mergeSortProcess(int[]arr,int lowIndex,int midIndex,int highIndex){
    int size = highIndex - lowIndex;
    int leftIndex = lowIndex;
    int rightIndex = midIndex;
    int[] extraArray = new int[size];
    int extraIndex = 0;
    //循环,
    while (leftIndex<midIndex && rightIndex< highIndex){
        //左区间的数小于右区间,则把左区间的数放到额外数组中
        if (arr[leftIndex]<=arr[rightIndex]){
            extraArray[extraIndex]=arr[leftIndex];
            leftIndex++;
        }else{
            //右区间的数小于左区间,则把右区间的数放到额外数组中
            extraArray[extraIndex]=arr[rightIndex];
            rightIndex++;
        }
        extraIndex++;
    }
    //当右区间结束,把左区间剩余的数全部依次放进额外数组中
    if (leftIndex<midIndex){
        while (leftIndex<midIndex){
            extraArray[extraIndex++]=arr[leftIndex++];
        }
    }else{
        //当左区间结束,把右区间剩余的数全部依次放进额外数组中
        while (rightIndex<highIndex){
            extraArray[extraIndex++]=arr[rightIndex++];
        }
    }
    //再把排序好的数组搬回到原数组中,完成合并
    for (int i = 0;i < size;i++){
        arr[i+lowIndex]=extraArray[i];
    }
}
public static void main(String[] args) {
    int[] arr = {3,4,9,8,6,3,4};
    myMergeSort(arr);
    for (int i = 0 ;i < arr.length;i++){
        System.out.print(arr[i]+" ");
    }
}

}
4.堆排序
(1)算法思想
堆排序是一种树形选择排序,在排序过程中可以把元素看成是一颗完全二叉树,每个节点都大(小)于它的两个子节点,当每个节点都大于等于它的两个子节点时,就称为大顶堆,也叫堆有序; 当每个节点都小于等于它的两个子节点时,就称为小顶堆。
1.将长度为n的待排序的数组进行堆有序化构造成一个大顶堆
2.将根节点与尾节点交换并输出此时的尾节点
3.将剩余的n -1个节点重新进行堆有序化
4.重复步骤2,步骤3直至构造成一个有序序列
(2)算法实现
import java.util.Arrays;

public class HeapSort {
public static int[] myHeapSort(int[] arr){
//建大堆
heap(arr,arr.length);
//进行选择,建堆之后,最大的数在0下标,交换0下标和无需区间最后一个下标的数
for(int i = 0;i < arr.length-1;i++){
int temp = arr[0];
arr[0] = arr[arr.length-i-1];
arr[arr.length-i-1] = temp;
//交换之后进行向下调整
adjustDown(arr,arr.length-i-1,0);
}
return arr;
}

private static void heap(int[] arr,int size) {
    //从第一个不是叶子结点的结点开始
    for (int i = (size-2)/2;i>=0;i--){
        adjustDown(arr,size,i);
    }
}

/**
 * 向下调整
 * @param arr 数组
 * @param size 需要调整的数组长度
 * @param index 调整的下标
 */
private static void adjustDown(int[] arr, int size, int index) {
    //有左孩子,即不是叶子结点
    while (2*index+1<size){
        int maxIndex = 2*index+1;
        //如果右孩子存在且右孩子大于左孩子,则最大孩子为右孩子,否则为左孩子
        if (maxIndex+1<size && arr[maxIndex]<arr[maxIndex+1]){
            maxIndex++;
        }
        // 如果最大孩子小于父亲,则停止循环
        if (arr[maxIndex]<=arr[index]){
            break;
        }
        //否则,交换最大孩子和父亲
        int temp = arr[index];
        arr[index] = arr[maxIndex];
        arr[maxIndex] =temp;

        //继续向下一层调整
        index = maxIndex;
    }
}

public static void main(String[] args) {
    int[] arr = {9,8,7,6,5,4};
    System.out.println(Arrays.toString(myHeapSort(arr)));
}

}
5.简单选择排序
(1)算法思想
把数组分成两个区间,左边是无序的,右边是有序的。在无序区间中找到最大的数,放到无序区间的最后一个。
(2)算法实现
public static int[] mySelectSort(int[] arr){
for(int i = 0;i < arr.length-1;i++){
//无序区间[0,arr.length-i)
//有序区间[arr.length-i,array.length)
int maxIndex = 0;
//找到无需区间最大数的下标
for (int j = 1;j < arr.length-i;j++){
if (arr[maxIndex]<arr[j]){
maxIndex=j;
}
}
//把无序区间的最大数和无序区间最后一个数进行交换
int m = arr[maxIndex];
arr[maxIndex] = arr[arr.length-i-1];
arr[arr.length-i-1] =m;
}
return arr;
}
6.直接插入排序
(1)算法思想
把数组分成两个区间,左边是有序的,右边是无序的。
每次在无序区间选择第一个元素,在有序区间插入合适的位置。
适用于大部分已有序的排好列。
(2)算法实现
public static int[] myInsertSort(int[] arr){
//有序区间:[0,i]
//无序区间:[i+1,arr.length-1]
for (int i = 0;i < arr.length-1;i++){
int ket = arr[i+1];
int j = 0;
//从有序区间最后一个开始循环,进行比较,如果小于,则往前移,否则插入到第j个位置的后面
for ( j = i;j>=0;j–){
if (ket<arr[j]){
arr[j+1]=arr[j];
}else {
break;
}
}
arr[j+1]=ket;
}
return arr;
}

7.希尔排序
(1)算法思想
希尔发明的,分组插排
(2)算法实现
public static int[] myShellSort(int[] arr){
int gap = arr.length/2;
while(true){
insertSortGap(arr,gap);
if (gap==1){
break;
}
gap = gap/2;
}
return arr;
}
public static void insertSortGap(int[] arr,int gap){
for (int i = gap;i < arr.length;i++){
int key = arr[i];
int j = 0;
for (j = i-gap;j>=0;j = j-gap){
if (arr[j]>key){
arr[j+gap] = arr[j];
}else{
break;
}
}
arr[j+gap]=key;
}
}

8.总结
排序算法

排序算法最好时间复杂度最坏时间复杂度平均时间复杂度空间复杂度稳定性
冒泡排序O(n)O(n^2)O(n^2)O(1)稳定
选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
插入排序O(n)O(n^2)O(n^2)O(1)稳定
希尔排序O(n)O(n^1.3)O(n^2)O(1)不稳定
堆排序O(nlog2)O(n^2)O(n^2O(1)不稳定
归并排序在这里插入图片描述O(n^2O(n^2O(n)稳定
快速排序O(n)O(n^2)O(n^2O(1)不稳定
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值