缘起:在写一道查找中位数的题,用冒泡排序有一个节点一直超时,就顺便学习一下快排
查找中位数代码
题目链接- 两个有序序列的中位数
(详参【陈越实验案例2-13】)
注释是我个人对这个排序原理的理解(可能会有错误)
关于后面那段递归,个人觉得理解的最好方法就是一步步调试
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int Find_mid(int a[],int K,int Left, int Right);
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int n;
cin >> n;
int* a = (int*)malloc(sizeof(int)*2*n);
for (int i = 0; i < 2 * n; i++)
cin >> a[i];
int Left = 0, Right = 2 * n - 1;
cout<< Find_mid(a,(2*n+1)/2,Left, Right);//(2*n+1)/2表示第K位数(n=5时k=5)
return 0;
}
//排完序还找到了中位数的位置
int Find_mid(int a[],int K,int Left, int Right)//K是从1开始数的
{
//思路:以第一个数为标准e,把小于e的放在左边,大于e的放在右边,如果e的位置恰好是k,那么e就是要找的,直接返回
//如果e的位置比k大(Left - L - 1 >= K),则第k大(中位数)数在e的左边,那么就递归左区间,否则(Left - L - 1 < K - 1)递归右区间
int L = Left, R = Right;
int e = a[Left];
while (1)
{
while (Left <= Right && e >= a[Left]) Left++;//一旦该位置的数比基准大就标记位置
while (Left<Right && e<a[Right]) Right--;//一旦该位置的数比基准小或者等于就标记位置
if (Left < Right)//把大的扔后面,小的留前面
swap(&a[Left], &a[Right]);
else break;//Left==Right(相遇了)此时这个点左边都比基准小,这个点自身包括右边都比大于或等于基准
//准备跳出去把基准换过来了
}
swap(&a[L], &a[Left-1]);//L(最开始的Left)是基准,相遇点包括相遇点(Left==Right)右边都是大于等于基准,相遇点左边都比基准小,那a[Left-1]自然也比基准小,a[Left]大于等于基准
//两个一换,相遇点左边依旧是比基准小的,所以是Left-1
if (Left - 1 - L +1> K)//Left - 1 - L >= K(书上这么写的)(左区间的元素个数大于K)
return Find_mid(a, K, L, Left - 2);//Left-1是当前基准(L---Left-2为左区间)
else if (Left - 1 - L +1 < K)//Left - 1 - L < K - 1(左区间的元素个数小于K)
return Find_mid(a, K - (Left - 1 -L) - 1, Left, R);//Left-1-L是左区间的大小,再减一是把基准那个点减掉(Left--R为右区间)
else return e;//基准的位置恰好是k Left-1-L+1==K,基准位置正好是第K个元素(可以从这一步往上推出上面两个判断)
}
下面这个代码和陈越老师的是一个思路的,但是在做选择题的时候
快速排序的比较原则是:(默认是这种比较方法)
从后面寻找比基准数小的数,与front交换;
从前面找比基准数大的数,与last交换。
快速排序代码
快排代码
void QuickSort(int arr[], int begin, int end)
{
if (begin > end) return;
int key = arr[begin];
int L = begin, R = end;
while (L != R)
{
while (arr[R] >= key && L < R) R--;
while (arr[L] <= key && L < R) L++;
if (L < R) {
swap(arr[L], arr[R]);
}
}
swap(arr[begin], arr[L]);
if (begin != L - 1) QuickSort(arr, begin, L - 1);
if (L + 1 != end) QuickSort(arr, L + 1, end);
}
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void swap(int* a, int* b);
void Print(int arr[], int n);
void QuickSort(int arr[], int begin, int end);
int main()
{
int n;
cin >> n;
int* arr = (int*)malloc(sizeof(int) * n);
for (int i = 0; i < n; i++)
cin >> arr[i];
QuickSort(arr, 0, n - 1);
Print(arr, n);
return 0;
}
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void QuickSort(int arr[], int begin, int end)
{
if (begin > end) return;//排序结束
int key = arr[begin];
int L = begin, R = end;
while (L != R)//L==R相遇跳出,基准数归位
{
//顺序不能倒
while (arr[R] >= key && L < R) R--;//找到小于基准的第一个数的位置
while (arr[L] <= key && L < R) L++;//找到大于基准的第一个数的位置
if (L < R) {
swap(&arr[L], &arr[R]);
}
}
swap(&arr[begin], &arr[L]);
//Print(arr, 6);
//这个和arr[L]交换还是arr[R]交换取决于前面和基准比较得过程
//本代码因为先比较R,所以能确保从右到左指向得所有数都大于等于基准,所以选择和arr[L]交换,这个数可能小于或者等于基准
if (begin != L - 1) QuickSort(arr, begin, L - 1);//左区间递归排序
if (L + 1 != end) QuickSort(arr, L + 1, end);//右区间递归排序
}
void Print(int arr[], int n)
{
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
}