分解代码快速理解 快速排序与归并排序

目录

1.快速排序

概念(来自于百度搜索):

(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

从以上的四点介绍中可以得出三点有效信息:
第一点和第二点为划分区间
第三点为交换
第四点为递归

从以上核心介绍中,可以写出以下快速排序的函数:
以下整合的C++代码:

#include <iostream>
using namespace std;
const int N = 100010;
int q[N];
void sort(int q[], int l, int r)
{
   //确立返回值
    if (l >= r) return;
    //这里注意一点,x是把数组进行分开,也是方便后面的递归,为了更好的排序把左右两个i,
    //j分别扩大范围
    int i = l - 1, j = r + 1, x = q[l + r >> 1];  
    //交换 把数组分为左右两个区间
    while (i < j)
    {
        while(q[++i]<x);
        while(q[--j]>x);
        if (i < j) {
            int t=q[i];
                q[i]=q[j];
                q[j]=t;
    }
    }
    //分开左右两个区间进行递归
    sort(q, l, j);
    sort(q, j + 1, r);
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
    sort(q, 0, n - 1);
    for (int i = 0; i < n; i ++ ) printf("%d ", q[i]);
    return 0;
}

2.归并排序

学习完快速排序后,归并排序的核心思想:
(1)确定分界点
(2)递归排序
(3)归并(合二为一)(难点/重点)
其中是把快速排序中的(2)与(3)进行代码上的交换。

在这里插入图片描述

算法模板:

//值得注意的是其需要一个临时数组进行存储
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;
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];
}

练习题:逆序对的数量

给定一个长度为 n
的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i
个和第 j
个元素,如果满足 i<j
且 a[i]>a[j]
,则其为一个逆序对;否则不是。
输入格式
第一行包含整数 n
,表示数列的长度。
第二行包含 n
个整数,表示整个数列。
输出格式
输出一个整数,表示逆序对的个数。
数据范围
1≤n≤100000,
数列中的元素的取值范围 [1,109]。
输入样例:
6
2 3 4 5 6 1
输出样例:
5

如果是用暴力的做法为O(n2) 用归并排序解决比暴力解决时间复杂度要低。

思路:利用归并排序的算法思想,讲归并排序分成两个部分,在输入数组中,可以分为三个部分。一个部分左边,一个部分为右边,还要一个部分为左右两边都有。
核心:这道题是利用归并排序的思路进行解决的,从归并的算法中可以看出利用递归可以把问题分解成为一个个子问题,利用子问题的特性进行把所有问题进行一个会合。
对于mid中我们只需要找到左边第一个大于B的数字A,那么A后面的数字都大于B。根据下标进行计算,则需要统计的数目为:mid-i+1

long mergeSort(int arr[],int l,int r){
  if(l>=r)return 0;
  int mid=l+r>>1;
  long res=mergeSort(arr,l,mid)+mergeSort(arr,mid+1,r);
  int tmp[l-r+1];//定义一个临时数组
  int k=0,i=l,j=mid+1;
  while(l<=mid&&j<=r){
    if(arr[i]<arr[j]) tmp[k++]=arr[i++];
    else{
       tmp[k++]=arr[j++];
       res+=mid-i+1;
         }
}
while(i<=mid) tmp[k++]=arr[i++];
while(j<=mid) tmp[k++]=arr[j++];
for(int i=l,j=0;i<=r;i++,j++) arr[i]=tmp[j];
return res;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值