排序>>交换排序

目录

交换排序

1.冒泡排序

2.快速排序

1.快速排序>>霍尔版

2.快速排序>>挖坑法

3.快速排序>>前后指针法

3.快速排序的优化


本文主要是对快速排序的进行说明,以及快速排序的一种优化方式

交换排序

1.冒泡排序

核心思想:相邻两个元素比较,如果前面 > 后面,就交换;每一轮把最大的元素 "冒泡" 到数组末尾,加上 flag 优化可以提前结束。

示例数组:[3, 1, 4, 2]

目标:排成 [1, 2, 3, 4]
冒泡排序的特性总结:

  • 冒泡排序是一种非常容易理解的排序

  • 时间复杂度:O(N^2)

  • 空间复杂度:O(1)

  • 稳定性:稳定

冒泡排序的步骤:

获取数组长度 n;

  1. 外层循环 i 从 0 到 n-2:
  2. 初始化标记 flag = false(标记本轮是否交换)
  3. 内层循环 j 从 0 到 n-1-i-1:
  4. 如果 array[j] > array[j+1](升序):交换两个元素,设置 flag=true
  5. 一轮内层结束后:
  6. 如果 flag == false:本轮没有交换,数组已有序,break 跳出外层循环
  7. 循环结束,排序完成。

代码示例:

java 复制代码
/**
     * 冒泡排序
     * 时间复杂度:O(N^2)
     * 空间复杂度:O(1)
     * 稳定性:稳定
     * @param array
     */
    public static void bubbleSort(int[] array){
        for(int i = 0; i < array.length - 1; i++){
            boolean flag = false;
            for(int j = 0; j < array.length -1-i;j++){
                if(array[j] > array[j+1]){
                    swap(array,j,j+1);
                    flag = true;
                }
            }
            if(!flag){
                break;
            }
        }
    }

2.快速排序

快速排序的特性总结:

  • 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(logN)
  • 稳定性:不稳定

1.快速排序>>霍尔版

Hoare 是快排原始版本,挖坑法、Lomuto 前后指针不一样。 核心思路:

  1. 选一个基准(一般选最左 / 最右)
  2. 左指针从左往右找大于基准 的;右指针从右往左找小于基准的
  3. 找到之后交换两个指针的值
  4. 直到左右指针相遇,相遇点就是划分边界,递归左右两个区间

图例:

代码示例:

java 复制代码
public static void quickSort(int[] array){
        quick(array,0,array.length - 1);
    }
    private static void quick(int[] array,int start,int end){
        if(start >= end){
            return;
        }
        int pivot = partitionHoare(array,start,end);
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }
//快速排序>>霍尔法
    private static int partitionHoare(int[] array, int left, int right) {
        int temp = array[left];
        int templeft = left;
        while(left < right){
            while(left < right && array[right] >= temp){
                right--;
            }
            while(left < right && array[left] <= temp){
                left++;
            }
            swap(array,left,right);
        }
        swap(array,left,templeft);
        return left;
    }

2.快速排序>>挖坑法

核心思想:先把基准挖出来,形成一个坑;右指针找比基准小的填到坑里,右指针位置变成新坑;左指针找比基准大的填到新坑,循环直到左右相遇,最后把基准放进这个坑。

特点:基准最后落在相遇位置,返回的 pivot 就是基准的最终下标

递归:quick(l, pivot-1) 和 quick(pivot+1, r)(和 Lomuto 一样,和 Hoare 霍尔不一样!)

图例:

代码示例:

java 复制代码
public static void quickSort(int[] array){
        quick(array,0,array.length - 1);
    }
    private static void quick(int[] array,int start,int end){
        if(start >= end){
            return;
        }
        int pivot = partitionDighole(array,start,end);
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }
//快速排序>>挖坑法
    private static int partitionDighole(int[] array, int left, int right) {
        int temp = array[left];
        while(left < right){
            while(left < right && array[right] >= temp){
                right--;
            }
            array[left] = array[right];
            while(left < right && array[left] <= temp){
                left++;
            }
            array[right] = array[left];
        }
        array[left] = temp;
        return left;
    }

3.快速排序>>前后指针法

核心思想:用两个指针,prev(慢指针,小于基准区域的最后一个位置)、cur(快指针,遍历扫描) 基准一般选最左边元素;cur 不断向后走,遇到比基准小的数,prev 先 ++,再交换 cur 和 prev; 遍历完之后,把基准和 prev 位置交换,prev 就是基准最终下标

递归写法:quick(l, pivot-1)、quick(pivot+1, r),和挖坑法一致,和 Hoare 霍尔不一样

图例:

代码示例:

java 复制代码
public static void quickSort(int[] array){
        quick(array,0,array.length - 1);
    }
    private static void quick(int[] array,int start,int end){
        if(start >= end){
            return;
        }
       

        int pivot =partitionFbpointer(array,start,end);
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }
//快速排序>>前后指针法
    private static int partitionFbpointer(int[] array, int left, int right) {
        int prev = left;
        int cur = left + 1;
        while(cur <= right){
            if(array[cur] < array[left] && array[++prev] != array[cur]){
                swap(array,cur,prev);
            }
            cur++;
        }
        swap(array,prev,left);
        return prev;
    }

3.快速排序的优化

在快速排序中,我们的理想的状态是将数据分成一个完全二叉树,而不是一个单列二叉树,这样的效率会大大折扣,所以我们会对快速排序进行一定的优化。

我们找到一组数据的第一元素和最后一个数据,利用这两个数据的下标来求中间值的下标,将这三个数中间大的数作为基准值。

代码示例:

java 复制代码
public static void quickSort(int[] array){

        quick(array,0,array.length - 1);

    }
    private static void quick(int[] array,int start,int end){
        if(start >= end){
            return;
        }

        int midlleIndex = getMidlle(array,start,end);
        swap(array,start,midlleIndex);

        int pivot = partitionHoare(array,start,end);
        quick(array,start,pivot-1);
        quick(array,pivot+1,end);
    }
 //三数取中法
    public static int getMidlle(int[] array,int left,int right){
        int mid = (left + right)/2;
        if(array[left] < array[right]){
            if(array[mid] < array[left]){
                return left;
            }else if(array[mid] > array[right]){
                return right;
            }else{
                return mid;
            }
        }else{
            if(array[mid] > array[left]){
                return left;
            }else if(array[right] > array[mid]){
                return right;
            }else{
                return mid;
            }
        }

对于上面多种快速排序的写法,其中挖坑法考的最多,所以挖坑法一定要学会,其他作为理解,但是不能不会

相关推荐
Wang's Blog1 小时前
MongoDB 地理位置上报实战:从接口设计到覆盖写入的完整实现
java·交友
努力努力再努力wz1 小时前
【Lua 入门系列】Lua数据结构:从 Table 出发,一文串联数组、链表、栈、队列、集合、映射与树的实现原理
数据结构·链表·lua
鬼手点金1 小时前
Skills:领域能力的可组合单元
java·人工智能·笔记·自动化·1024程序员节
dialect_10 小时前
KMP算法
开发语言·c++·算法
captain37610 小时前
MyBatis(入门5)其他查询操作
java·数据库·spring boot·mybatis
reikocao10 小时前
卡尔曼滤波的动态机制:P如何改变融合权重
算法
Novproxy_Z10 小时前
商用代理避坑:如何识别商家拿机房 IP 冒充住宅 IP
java·网络·tcp/ip
漂流瓶jz11 小时前
UVA-1612 猜名次 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·题解·排序·aoapc·算法竞赛入门经典
吞下星星的少年·-·11 小时前
Div.2 CF 1130B题(构造,贪心)
算法·贪心·构造