算法_归并排序

题目:

给定你一个长度为 n 的整数数列。

请你使用归并排序对这个数列按照从小到大进行排序。

并将排好序的数列按顺序输出。

快排和归并排序的时间复杂度都是  n * log2 (n) 

思想: 

分治(找分界点 递归排序)

快排是找一个  数组中的一个  值进行排序

而归并排序是以  中间点(数组的左右边界下标索引的平均值) 为分界点

1、确定分界点,以中间点((left + right) / 2 是左右边界下标索引的平均值)划分

2、递归排序左边 和 右边。(递归完后,左右两边就会变为有序的列表)

3、归并(难点),将两个有序的数组  归并为   一个有序的数组

      我们使用双指针排序进行 归并,期间用一个临时数组temp[] ,记录每次调用排好的数据,排好此次调用排序方法的数据后 将数据赋给 原数组

临时数组temp[]的一个说明

    这里特地对临时数组temp[]的使用 说明 因为吃坑了,

   在递归中我们给定temp的大小不能直接是array.length而应该根据merge_Sort方法中形参而定,即根据左右边界left 和right来定,设置为right - left + 1(要排序的数据的数量,这样可以确保排完序后没有位置是空的,不会造成不必要的空值影响结果。

//right - left + 1是因为每次调用该方法需要排序的元素个数 就是 right - left + 1
int temp[] = new int[right - left + 1];//创建临时数组 存储 此次须排序的数据

还有一点关于临时数组的说明就是,临时数组排好序后给原数组赋值时,要根据其对应的索引位置直接赋值到  原数组相同的索引位置上,这一点可以根据 left和 right来 实现

for (int m = left, t = 0; m <= right; m++, t++) {
    //m记录的是 此次排序的数据 在原数组对应的索引位置,所以直接将其赋值给原索引位置
    //left 和 right就方便计算 其原始索引位置
    array[m] = temp[t];
}

     归并举例:

例如 数组 5 3 7 1 9 4 2 8 5 10,经过上面的中间点(0 + 9 >> 1 =  4,中间点的索引为4)分解后  ,变为两个数组  一个是索引从0到4 的 [5 3 7 1 9] 另一个是 索引从5到9的 [4 2 8 5 10]

首先经过 上面的递归后,左右两个数组均为从小到大的有序数组 

即[1 3 5 7 9] 和 [2 4 5 8 10]

因为两个数组 均是 有序数组,左侧的均为 min值 ,所以两个指针都放在左侧

循环比较两个指针所对应的数字,哪个指针对应的数字小,就将该数字加入到temp数组,并将指针加1,
while(i <= mid && j <= right){
            if(array[i] <= array[j]){
                temp[k++] = array[i++];
            }else{
                temp[k++] = array[j++];
            }
        }

 因为1比较小 所以将 1加入到 临时数组中,并将索引 ++

继续比较发现  2小于3 于是 将 2加入结果  并将下面的索引++

。。。。

。。。。

不断循环

 

最后两个指针一个 是 9 一个是10,比较后 将9 加入临时数组 ,并将索引++

注意此时 第一个指针已经 大于了mid,不符合循环条件了,所以跳出循环,

但是还有一部分 需要添加到临时数组(剩下的都是已经递归排好序的,所以直接循环添加入临时数组即可)

//只要左半边没有循环完(i <= mid),就将 左半边的都加到 temp数组中
while(i <= mid){temp[k++] = array[i++];}
//只要右半边没有循环完(j <= right),就将 右半边的都加到 temp数组中
while(j <= right){temp[k++] = array[j++];}
由于结果存储在 临时数组temp中,现在需要将 其复制回原数组
        for (int m = left, t = 0; m <= right; m++, t++) {
            //m记录的是 此次排序的数据 在原数组对应的索引位置,所以直接将其赋值给原索引位置
            //left 和 right就方便计算 其原始索引位置
            array[m] = temp[t];
        }

 

整体代码

package algorithm_;

/**
 * @author TJU第一炼丹师
 * @since 2024-02-22 15:55:20
 */
import java.util.*;
public class merge_Sort {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int array[] = new int[n];
        for (int i = 0; i < n; i++) {
            array[i] = sc.nextInt();
        }

        merge_Sort(array, 0, n - 1);
        for (int i = 0; i < n; i++) {
            System.out.print(array[i] + " ");
        }
    }

    public static void merge_Sort(int array[], int left, int right){
        if(left >= right) return;
        //1、设置分界点
        int mid = left + right >> 1;
        //2、递归
        merge_Sort(array, left, mid);
        merge_Sort(array, mid + 1, right);
        //3、归并 将两个有序数组 合二为一 变成一个有序数组
        //right - left + 1是因为每次调用该方法需要排序的元素个数 就是 right - left + 1
        int temp[] = new int[right - left + 1];//创建临时数组 存储 此次须排序的数据
        int k = 0;//表示在归并过程中,临时结果数组 temp中已有多少个数字了
        int i = left;//i是指针 指向 左边数组的起点
        int j = mid + 1;//j是指针 指向 右边数组的起点
        //比较两个指针所对应的 数字,哪个指针对应的数字小,就将该数字加入到temp数组,并将指针加1
        while(i <= mid && j <= right){
            if(array[i] <= array[j]){
                temp[k++] = array[i++];
            }else{
                temp[k++] = array[j++];
            }
        }
        //只要左半边没有循环完(i <= mid),就将 左半边的都加到 temp数组中
        while(i <= mid){temp[k++] = array[i++];}
        //只要右半边没有循环完(j <= right),就将 右半边的都加到 temp数组中
        while(j <= right){temp[k++] = array[j++];}

        //由于结果存储在 临时数组temp中,现在需要将 其复制回原数组
        //
        for (int m = left, t = 0; m <= right; m++, t++) {
            //m记录的是 此次排序的数据 在原数组对应的索引位置,所以直接将其赋值给原索引位置
            //left 和 right就方便计算 其原始索引位置
            array[m] = temp[t];
        }
    }
}

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
归并排序(Merge Sort)是一种稳定的、基于比较的排序算法,最坏时间复杂度为 O(nlogn)。其基本思想是将待排序序列分成若干个子序列,每个子序列都是有序的,然后将子序列合并成整体有序的序列。 归并排序的实现方法有两种:自顶向下和自底向上。 自顶向下的归并排序算法实现: 1. 将待排序序列分成两个子序列,分别对这两个子序列进行递归排序。 2. 将两个已经排好序的子序列合并为一个有序序列。 自底向上的归并排序算法实现: 1. 将待排序序列每个元素看成一个独立的有序序列,进行两两合并。 2. 得到 n/2 个长度为 2 的有序序列,再两两合并。 3. 重复步骤 2,直到得到一个长度为 n 的有序序列。 下面是自顶向下的归并排序算法的实现代码(使用了递归): ``` void MergeSort(int arr[], int left, int right) { if (left >= right) return; int mid = left + (right - left) / 2; MergeSort(arr, left, mid); MergeSort(arr, mid + 1, right); int* temp = new int[right - left + 1]; int i = left, j = mid + 1, k = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) temp[k++] = arr[i++]; else temp[k++] = arr[j++]; } while (i <= mid) temp[k++] = arr[i++]; while (j <= right) temp[k++] = arr[j++]; for (int p = 0; p < k; p++) arr[left + p] = temp[p]; delete[] temp; } ``` 下面是自底向上的归并排序算法的实现代码(使用了迭代): ``` void MergeSort(int arr[], int n) { int* temp = new int[n]; for (int len = 1; len < n; len *= 2) { for (int left = 0; left < n - len; left += len * 2) { int mid = left + len - 1; int right = min(left + len * 2 - 1, n - 1); int i = left, j = mid + 1, k = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) temp[k++] = arr[i++]; else temp[k++] = arr[j++]; } while (i <= mid) temp[k++] = arr[i++]; while (j <= right) temp[k++] = arr[j++]; for (int p = 0; p < k; p++) arr[left + p] = temp[p]; } } delete[] temp; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值