【数据结构】八大排序算法

目录

一、冒泡排序

1)思路:

2)代码实现:

3)优化:

4)时间复杂度分析:O(n^2)

二、选择排序

1)思路:

2)代码:

3)时间复杂度分析:O( n^2)

三、插入排序

1)思路:

2)代码:

3)时间复杂度分析:O(n^2)

四、希尔排序--移位法(推荐使用)

1)思路:

2)代码:

3)时间复杂度分析:O( Nlog(N) )

五、希尔排序--交换法(不推荐使用)

1)思路:

2)代码:

3)时间复杂度分析:O( Nlog(N) )

六、快速排序

1)思路:

2)代码:

3)时间复杂度分析:O( Nlog(N) ) - O(n^2)

七、归并排序

1)思路:

2)代码:

3)时间复杂度分析:O( Nlog(N) )

八、基数排序(桶排序)

1)思路:

2)代码:

3)时间复杂度分析:O( Nlog(N) )

九、堆排序

1)思路:

2)代码:

3)时间复杂度分析:O( Nlog(N) )


一、冒泡排序

1)思路:

第i(i = 0,1,2,3,4,5...)个数比较【数组长度- 1 】次,每次循环确定一个最大/最小值,比较【数组长度 - 1 - i】次

2)代码实现:

static void sort(int a[]){
    for (int i = 0; i < a.length - 1; i++) {
        for (int j = 0; j < a.length - 1 - i; j++) {
            // 交换
            if(a[j] > a[j + 1]){
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }
    // 输出排序后的数组
    System.out.println(Arrays.toString(a));
}

3)优化:

① 如果有序就不进行比较

static void sort1(int a[]){
    // 是否进行了交换
    boolean target = false;
    for (int i = 0; i < a.length - 1; i++) {
        for (int j = 0; j < a.length - 1; j++) {
            // 交换
            if(a[j] > a[j + 1]){
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
                target = true;
            }
            if(!target){
                continue;
            }
        }
    }
    // 输出排序后的数组
    System.out.println(Arrays.toString(a));
}
② 控制循环次数
static void sort2(int a[]){
    // 记录交换的最后一次
    int count = a.length - 1;
    while (true){
        int num = 0;
        for (int j = 0; j < count; j++) {
            // 交换
            if(a[j] > a[j + 1]){
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
                num = j;
            }
        }
        count = num;
        // 如果最后一次交换下标为0,退出
        if(count == 0)
            break;
    }
    // 输出排序后的数组
    System.out.println(Arrays.toString(a));
}

4)时间复杂度分析:O(n^2)

二、选择排序

1)思路:

第一次从arr[0] ~ arr[n - 1]中选取最小值,和arr[0]交换、第二次从arr[1] ~ arr[n - 1]中选取最小值,和arr[1]交换、第i次从arr[i - 1] ~ arr[n - 1]中选取最小值,和arr[i - 1]交换

2)代码:

public static void choiceSort(int arr[]) {
    // 最小数
    int min = 0;
    // 最小数的下标
    int minIndex = 0;
    // 是否交换
    boolean isFlag = false;
    for (int i = 0; i < arr.length; i++) {
        // 最小的值默认为当前值
        min = arr[i];
        // 最小下标默认为当前值的下标
        minIndex = i;
        for (int j = i + 1; j < arr.length; j++) {
            // 找到最小值
            if (arr[j] < min) {
                min = arr[j];
                minIndex = j;
                isFlag = true;
            }
        }
        // 如果没交换,则代表有序
        if (!isFlag) break;
        arr[minIndex] = arr[i];
        arr[i] = min;
    }
    System.out.println(Arrays.toString(arr));
}

3)时间复杂度分析:O( n^2)

三、插入排序

1)思路:

构建有序序列,每次在未排序数组中取出一个数据,与有序序列中的数据进行比较,找到合适的位置插入。

2)代码:

// 插入排序
public static void insertSort(int[] arr){
    for (int i = 1; i < arr.length; i++){
        // 存储要插入的数
        int insertVal = arr[i];
        // 要比较的下标
        int insetIndex = i - 1;
        while (insetIndex >= 0 && insertVal < arr[insetIndex]){
            arr[insetIndex + 1] = arr[insetIndex];
            insetIndex--;
        }
        // 插入操作
        arr[insetIndex + 1] = insertVal;
    }
    System.out.println(Arrays.toString(arr));
}

3)时间复杂度分析:O(n^2)

四、希尔排序--移位法(推荐使用)

1)思路:

把记录按下标的一定增量(gap)进行分组,对每组使用直接插入排序算法排序,增量每次递减,当增量减至1时,整个文件被分为一组,变成一组有序数据。
移位法:
// 先保存原数据
int insertVal = arr[i];
// 移动
          arr[i] = arr[i - gap];
           // 赋值
arr[i - gap] = insertVal;

2)代码:

// 希尔排序--移位法
public static void shellSort2(int[] arr){
    // 循环次数(步长每次/2)
    for (int gap = arr.length / 2; gap > 0; gap /= 2){
        // 需要比较的组数
        for (int i = gap; i < arr.length; i++) {
            // 保存原数据
            int insertVal = arr[i];
            // 从小到大排序,如果后一个数大于前一个数,则无需比较
            if(arr[i] < arr[i - gap]){
                // 移动
                arr[i] = arr[i - gap];
                // 赋值
                arr[i - gap] = insertVal;
            }
        }
    }
    System.out.println(Arrays.toString(arr));
}

3)时间复杂度分析:O( Nlog(N) )

五、希尔排序--交换法(不推荐使用)

1)思路:

把记录按下标的一定增量(gap)进行分组,对每组使用直接插入排序算法排序,增量每次递减,当增量减至1时,整个文件被分为一组,变成一组有序数据。
交换法:
int temp = arr[i]; 
arr[i] = arr[i + 1]; 
arr[i + 1] = arr[i];

2)代码:

// 希尔排序--交换法
public static void shellSort1(int[] arr){
    int temp = 0;
    // 循环次数(步长每次/2)
    for (int gap = arr.length / 2; gap > 0; gap /= 2){
        // 需要比较的组数
        for (int i = gap; i < arr.length; i++) {
            // 每组比较的数
            for (int j = i - gap; j >= 0; j -= gap) {
                // 交换
                if(arr[j] > arr[j + gap]){
                    temp = arr[j];
                    arr[j] = arr[j + gap];
                    arr[j + gap] = temp;
                }
            }
        }
    }
    System.out.println(Arrays.toString(arr));
}

3)时间复杂度分析:O( Nlog(N) )

六、快速排序

1)思路:

① 确定分界点x(一般是取左端点、右端点、一半 )
调整范围( * 重点 * )使得左边区域所有的数都<=x,右边区域所有的数都>=x
③  递归处理左右两段

2)代码:

static void quick_sort(int q[], int l, int r){
    //如果数组中没有数据,或者只有一个数据,则不用进行排序操作
    if (l >= r) return;
    //左右指针的初始位置,分界点的位置
    int i = l - 1, j = r + 1, x = q[l+r >> 1];
    while (i < j) {
        do i++; while (q[i] < x);
        do j--; while (q[j] > x);
        if(i < j) {
            int temp = q[i];
            q[i] = q[j];
            q[j] = temp;
        }
    }
    quick_sort(q, l, j);
    quick_sort(q, j+1, r);
}

3)时间复杂度分析:O( Nlog(N) ) - O(n^2)

七、归并排序

1)思路:

利用归并思想实现的排序算法,采用经典的分治策略将一个问题拆分成一些小的问题(分),然后递归求解,求解后将各个小问题的答案合并在一起(治)。

2)代码:

static void merge_sort(int q[], int l, int r){
    if(l >= r) return;
    int mid = l+r >> 1;
    merge_sort(q, l, mid);
    merge_sort(q, mid + 1, r);
    int k = 0, i = l, j = mid + 1;
    int tmp[] = new int[r - l + 1];
    while (i <= mid && j <= r){
        if(q[i] <= q[j]) tmp[k++] = q[i++];
        else tmp[k++] = q[j++];
    }
    while(i <= mid) tmp[k++] = q[i++];
    while(j <= r) tmp[k++] = q[j++];
    for (i = l, j = 0; i <= r; i++, j++)
        q[i] = tmp[j];
}

3)时间复杂度分析:O( Nlog(N) )

八、基数排序(桶排序)

1)思路:

将整数按位切割成0-9之间的数字,放在不同的桶(二维数组bucket[][])中,按位比较每个数大小,循环原数组中数字长度最大个次数。

2)代码:

// 基数排序
public static void radixSort(int[] arr){
    // 定义二维桶
    int[][] bucket = new int[10][arr.length];
    // 定义每个桶中存放有多少数据
    int[] bucketCount = new int[10];
    // 求出最大值
    int maxNum = arr[0];
    for (int i = 0; i < arr.length; i++) {
        if(maxNum < arr[i]) maxNum = arr[i];
    }
    // 求出最大值的位数
    int maxLength = (maxNum + "").length();
    // 循环
    for (int i = 0, n = 1; i < maxLength; i++, n *= 10){
        for (int j = 0; j < arr.length; j++){
            // 求出各位数
            int num = arr[j] / n % 10;
            // 放入桶中,并记录每个桶中数据的个数
            bucket[num][bucketCount[num]++] = arr[j];
        }
        int index = 0;
        // 取出每轮的数据
        for (int k = 0; k < bucketCount.length; k++) {
            if(bucketCount[k] != 0){
                for (int m = 0; m < bucketCount[k]; m++) {
                    // 取出数据,放入原数组中
                    arr[index++] = bucket[k][m];
                }
            }
            // 将记录每个桶中数据存放个数的数组置为空,以便下次使用
            bucketCount[k] = 0;
        }
    }
    System.out.println(Arrays.toString(arr));
}

3)时间复杂度分析:O( Nlog(N) )

九、堆排序

1)思路:

① 将待排序的序列构造成一个大顶堆或小顶堆
② 此时,整个序列的最大值或最小值就是堆顶的跟结点
③ 将其与末尾元素进行交换,此时末尾就是最大值
④ 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的此小值,反复执行,便能得到一个有序序列

2)代码:

/**
* 堆排序
* @param arr 要排序的数组
*/
public static void heapSort(int arr[]) {
    int temp = 0;
    for (int i = arr.length / 2 - 1; i >= 0; i--) {
        adJustHeap(arr, i, arr.length);
    }
    for (int i = arr.length - 1; i > 0; i--) {
        // 交换
        temp = arr[i];
        arr[i] = arr[0];
        arr[0] = temp;
        adJustHeap(arr, 0 , i);
    }
    System.out.println(Arrays.toString(arr));
}
/**
* 将一个数组调整成一个大顶堆
* @param arr 数组
* @param i 从哪个位置调整
* @param length 长度
*/
public static void adJustHeap(int[] arr, int i, int length) {
    // 先取出当前元素,保存在临时变量
    int temp = arr[i];
    for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
        if (k+1 < length && arr[k] < arr[k + 1]) k++;
        if (arr[k] > temp) {
            arr[i] = arr[k];
            i = k;
        } else {
            break;
        }
    }
    // 当for循环结束后,已经将以i为父节点的树的最大值放在了顶部
    arr[i] = temp;
}

3)时间复杂度分析:O( Nlog(N) )

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值