2020.8.26 排序算法
一.简单模板
1.选择排序:时间复杂度o()
每次找到最小的一个,然后与没排的第一个元素交换
void choseSort(int arr[], int n) {
int i, j;
int min, temp;
// 每次从未排序的部分选出一个最小的元素,最后一次只剩一个元素未排序
// 此时实际上已经排好序,故只需要n-1次外层大循环
for (i = 0; i < n - 1; ++i) {
min = i; // 假定未排序部分的第一个元素为最小的元素
// 遍历剩下的部分,找到最小的元素
for (j = i + 1; j < n; ++j) {
if (arr[j] < arr[min]) {
min = j;
}
}
// 如果第一个元素就是最小的元素,就不需要交换了
if (min != i) {
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
})
2.冒泡排序:时间复杂度o()
一步一步来,每个元素都只跟他后面一个比,大于就交换,任务就是将每一个元素送到末尾。但是存在有可能几轮就排序好了,但是还在比较,所以增加flag元素单标此次循环比较有没有移动。
代码:
void bubblingSort(int arr[], int n) {
int i, j, temp;
int flag = 0; // flag用来校验每轮循环有没有移动元素,0为没有移动,1为移动
// 每次将一个元素送到末尾,n个元素,执行n次
for (i = 0; i < n; ++i) {
flag = 0;
// 之前的循环已经将i个元素送到末尾,不需要再次比较,故减去,因为跟后一个元素比较,为了避免溢出,故减一
for (j = 0; j < n - i - 1; ++j) {
// 如果当前的元素比后一个元素小,就交换
if (arr[j] > arr[j + 1]) {
flag = 1; // 有数据交换
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
// 没有数据交换,提前结束
if (flag == 0) {
break;
}
}
}
3.插入排序 时间复杂度o()
将一个数放到一个有序队列中,从末尾开始一个个比较,大于往后移,直到找到合适的位置。
代码:
void insert_sort(int arr[], int len)
{
for (int i = 1; i < len; ++i)
{
if (arr[i] < arr[i - 1]) {
int temp = arr[i];
int j = i - 1;
for (; j >= 0 && arr[j]>temp; --j) {
arr[j + 1] = arr[j];//交换位置
}
arr[j + 1] = temp;
}
}
}
二、进阶模板
1.快速排序 时间复杂度o()这个递归比非递归快是怎么回事????
int partion(int a[], int left, int right)
{
//取最右边的元素作划分元素
int temp = a[right];
//记录 i = left, j = right
int i = left, j = right-1;
//循环直到左右指针相遇
while(true)
{
//从左边开始扫描,当出现比划分元素大的元素,扫描停止
while(temp > a[i])
{
i++;
}
//从右边进行扫描,当出现比划分元素小的元素,扫描停止
while(temp < a[j] && j >= left)
{
j--;
}
//如果 i >= j, 循环截止,下面的交换不执行
- · if(i >= j) break;
- · //交换停止时的元素
- · swap(a[i], a[j]);
- · }
- · //交换该元素与划分元素
- · swap(a[i], a[right]);
- · Print(a, 0, 6);
- · //printf("i = %d", i);
- · //划分过程结束
- · return i;
- · }
- · //快速排序
递归实现:
- · void qsort(int a[], int left, int right)
- · {
- · //排序完成,循环截止
- · if(right <= left)
- · return;
- · //做划分
- · int i = partion(a, left, right);
- · //对左部分排序
- · if(left < (i-1))
- · printf("对%d~%d排序 ", left, i-1), qsort(a, left, i-1);
//对右部分排序
if(right > (i+1))
printf("对%d~%d排序 ", i+1, right), qsort(a, i+1, right);
}
非递归实现:
· void qsort(int a[], int left, int right)
- · {
- · int i;
- · //定义栈s
- · stack<int> s;
- · //先判断栈是否为空
- · while(!s.empty())
- · {
- · //若栈不为空,将栈中元素移出
- · s.pop();
- · }
- · //将right入栈
- · s.push(right);
- · //将left入栈
- · s.push(left);
- · //while循环,当栈为空时,循环结束
- · while(!s.empty())
- · {
- · //元素left出栈
- · left = s.top(), s.pop();
- · //元素right出栈
- · right = s.top(), s.pop();
- · //判断left与right的关系,如果left>=right,continue
- · if(left >= right)
- · {
- · continue;
- · }
- · //作划分
- · i = partion(a, left, right);
- · //比较两个子数组的大小
- · //将子数组中的较大者压入栈
- · if((i-1-left) > (right-i-1))
- · {
- · s.push(i-1);
- · s.push(left);
- · s.push(i+1);
- · s.push(right);
- · }
- · else
- · {
- · s.push(i+1);
- · s.push(right);
- · s.push(i-1);
- · s.push(left);
- · }
- · }
- · }
三、例题
题目描述
输入 n(n<5000000 且 n为奇数) 个数字 ai(0<ai<109),输出这些数字的第 k 小的数。最小的数是第 0 小。
输入格式
无
输出格式
无
输入输出样例
输入 #1
5 1
4 3 2 1 5
输出 #1
2
代码:
#include<bits/stdc++.h>using namespace std;int x[5000005],k;void qsort(int l,int r){
int i=l,j=r,mid=x[(l+r)/2];
do
{
while(x[j]>mid)
j--;
while(x[i]<mid)
i++;
if(i<=j)
{
swap(x[i],x[j]);
i++;
j--;
}
}
while(i<=j);
//快排后数组被划分为三块: l<=j<=i<=r
if(k<=j) qsort(l,j);//在左区间只需要搜左区间
else if(i<=k) qsort(i,r);//在右区间只需要搜右区间
else //如果在中间区间直接输出
{
printf("%d",x[j+1]);
exit(0);
}
}int main(){
int n;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
scanf("%d",&x[i]);
qsort(0,n-1);
}