总结:八大排序算法

目录

一、插入排序

1、直接插入排序

 

2、希尔排序

 

二、选择排序

1、简单选择排序

 

2、堆排序

 

三、交换排序

1、冒泡排序

 

2、快速排序

 

四、归并排序


一、插入排序

1、直接插入排序

它的算法思想是:把要排序的数组分为了两个部分, 一部分是数组的全部元素(除去待插入的元素), 另一部分是待插入的元素; 先将第一部分排序完成, 然后再插入这个元素. 其中第一部分的排序也是通过再次拆分为两部分来进行的。

在这里默认arr[0]是排完序的那部分,arr[j] = arr[j - 1];表示如果当前要排序的数比从后向前遍历的数小,那么就向后移, arr[j] = temp;表示在对应的位置插入数值。

int[] arr = {1,4,2,8,74,12,9,30,8,11,22,87,12,44,28};
int gap = 1,i,j;
int temp;
int len = arr.length;
for(i = 1;i < len;i++){
    temp = arr[i];
    for(j = i;j >= 1&&arr[j - 1] > temp;j -= 1){
        arr[j] = arr[j - 1];
    }
    arr[j] = temp;
}

平均时间复杂度

最好情况

最坏情况

空间复杂度

O(n²)

O(n)

O(n²)

O(1)

 

2、希尔排序

将待排序数组按照步长gap进行分组,然后将每组的元素利用直接插入排序的方法进行排序;每次再将gap折半减小,循环上述操作;当gap=1时,利用直接插入,完成排序。)

实际上,直接插入排序是把步长为1的两个值进行比较,而希尔排序是将步长表示成了gap。这是对直接插入排序的一种优化。

int[] arr = {1,4,2,8,74,12,9,30,8,11,22,87,12,44,28};

int gap = 1,i,j;
int temp;
int len = arr.length;
while(gap < len /3){
    gap = gap * 3 + 1;
}
for(;gap > 0; gap /= 3){
    for(i = gap ; i < len;i++){
        temp = arr[i];
        for(j = i;j >= gap && arr[j - gap]> temp;j -= gap){
            arr[j] = arr[j - gap];
        }
        arr[j] = temp;
    }
}

平均时间复杂度

最好情况

最坏情况

空间复杂度

O(nlog2 n)

O(nlog2 n)

O(nlog2 n)

O(1)

 

二、选择排序

1、简单选择排序

这个算法比较简单,就是每次找到最小的数值,然后保存他的下标与前面第1、2.....arr.length-1交换。

int[] arr = {1,4,2,8,74,12,9,30,8,11,22,87,12,44,28};
for(int i = 0;i < arr.length - 1;i++){
    int min = i;
    for(int j = i + 1;j < arr.length;j++){
        if(arr[j] < arr[i]){
            min = j;
        }
    }
    if(min != i){
        int temp = arr[i];
        arr[i] = arr[min];
        arr[min] = temp;
    }
}

O(n²)

O(n²)

O(n²)

O(1)

 

2、堆排序

首先先将数组转换成堆,这里是大顶堆。然后通过遍历每次取大顶堆堆顶元素,再重新heapify。完成排序。

public static void main(String[] args) {
//        int[] arr = {1,4,2,8,74,12,9,30,8,11,22,87,12,44,28};
        int[] arr = {2,5,3,1,10,4};
        heap_sort(arr,arr.length);
        for(int k = 0;k < arr.length;k++){
            System.out.print(arr[k] + " ");
        }

    }
    //通过堆排序,输出
    public static void heap_sort(int[] arr,int len){
        build_heapify(arr,len);
        for(int i = len - 1;i >= 0; i--){
            swap(arr,i,0);
            heapify(arr,i,0);
        }
    }
    //构建整个堆,每一个堆节点
    public static void build_heapify(int[] arr,int len){
        int last_node_index = len - 1;
        int parent_index = (last_node_index - 1) / 2;
        for(int i  = parent_index;i >= 0;i--){
            heapify(arr,len,i);
        }
    }
    //对单个堆进行排序
    public static void heapify(int []arr,int len,int i){
        if(i >= len)
            return ;
        int left = i * 2 + 1;
        int right = i * 2 + 2;
        int max = i;
        if(left < len && arr[max] < arr[left])
            max = left;
        if(right < len &&arr[max] < arr[right])
            max = right;
        if(max != i){
            swap(arr,max,i);
            heapify(arr,len,max);
        }
    }
    public static void swap(int[] arr,int x,int y){
        int temp = arr[x];
        arr[x] = arr[y];
        arr[y] = temp;
    }

平均时间复杂度

最好情况

最坏情况

空间复杂度

O(nlog2n)

O(nlog2n)

O(nlog2n)

O(1)

 

三、交换排序

1、冒泡排序

这个算法也比较简单,直接将最大值冒泡到最后一个位置。

for(int i = arr.length;i >= 0;i--){
    for(int j = 0;j < i&& j + 1 < i;j++){
        if (arr[j] > arr[j + 1]){
            int temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }
    }
}

平均时间复杂度

最好情况

最坏情况

空间复杂度

O(n²)

O(n)

O(n²)

O(1)

 

2、快速排序

快速排序是对冒泡排序的一种优化,这个算法的思想是:选定一个基准值,使这个基准值的左边都是小于它,右边都是大于它的值。

public static void quick_sort(int[] arr ,int low,int high){
    if(arr.length < 0 || low > high)
        return ;
    int left = low;
    int right = high;
    //保存基准值
    int temp = arr[left];
    while(left < right){
        //从后向前找到比基准小的元素
        while(left < right && arr[right] >= temp){
            right--;
        }
        arr[left] = arr[right];
        //从前往后找到比基准大的元素
        while(left < right && arr[left] <= temp){
            left++;
        }
        arr[right] = arr[left];
    }
    arr[left] = temp;
    quick_sort(arr,low,left - 1);
    quick_sort(arr,left + 1,high);
}

O(nlog₂n)

O(nlog₂n)

O(n²)

O(1)(原地分区递归版)

 

四、归并排序

思想:

①. 将序列每相邻两个数字进行归并操作,形成 floor(n/2)个序列,排序后每个序列包含两个元素;

②. 将上述序列再次归并,形成 floor(n/4)个序列,每个序列包含四个元素;

③. 重复步骤②,直到所有元素排序完毕。

public static int[] mergingSort(int[] arr){
    if(arr.length <= 1)
        return arr;
    int num = arr.length >> 1;
    int[] arrLeft = Arrays.copyOfRange(arr,0,num);
    int[] arrRight = Arrays.copyOfRange(arr,num,arr.length);
    return mergeTwoArray(mergingSort(arrLeft),mergingSort(arrRight));
}

public static int[] mergeTwoArray(int[] arr1,int[] arr2){
    int[] result = new int[arr1.length + arr2.length];
    int i = 0,j = 0, k = 0;
    while(i < arr1.length && j < arr2.length){
        if(arr1[i] < arr2[j]){
            result[k++] = arr1[i++];
        }else{
            result[k++] = arr2[j++];
        }
    }
    while(i < arr1.length){
        result[k++] = arr1[i++];
    }
    while(j < arr2.length){
        result[k++] = arr2[j++];
    }
    return result;
}

五、基数排序

利用桶排序的思想

public static void radixSort(int[] arrays){
    int max = findMax(arrays);

    //遍历位数
    for(int i = 1;max / i > 0;i *= 10){
        int[][] buckets = new int[arrays.length][10];
        //获取每一位数字(个、十、百、千位...分配到桶子里)
        for(int j = 0;j < arrays.length;j++){
            int num = (arrays[j] / i) % 10;
            //将其放入桶子里
            buckets[j][num] = arrays[j];
        }
        //回收桶子里的元素
        int k = 0;

        for(int j = 0;j < 10;j++){
            for(int y = 0;y < arrays.length;y++){
                if(buckets[y][j]!=0){
                    arrays[k++] = buckets[y][j];
                }
            }
        }
    }
}

public static int findMax(int[] arrays){
    int max = 0;
    for(int i = 0;i < arrays.length;i++){
        if(arrays[i] > max){
            max =arrays[i];
        }
    }
    return max;
}
发布了134 篇原创文章 · 获赞 91 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/weixin_44588495/article/details/104082500