一、排序
1.快速排序
基本思想
分治
基本思路
- 确定分界点(任意一个数都可以);
- 调整数字位置使得x左边的值均小于等于x,右边的值均大于等于x;
- 递归处理左右两个子序列。
源代码
#include <iostream>
using namespace std;
void quickSort(int q[], int l, int r)
{
if(l >= r) return;//数组长度为1则直接返回
int x = q[(l+r) >> 1];//取数组q的中间值
int i = l - 1, j = r + 1;
//定义两个指针,i指向数列q的最左边,j指向数列q的最右边
while(i < j)//i与j相遇或者互相穿过时结束
{
do i ++; while(q[i] < x);//保证x左边的数都是小于x的
do j --; while(q[j] > x);//保证x右边的数都是大于x的
if(i < j)//此时i可能大于等于j
swap(q[i], q[j]);//交换i指向的数字与j指向的数字的位置
}
quickSort(q, l, j);//递归处理左边的数组,注意边界值
quickSort(q, j + 1, r);//递归处理右边的数组,注意边界值
}
注意事项
1.第一次调用quickSort时,q为待排序数组,l为0,r为数组最后一个元素的下标。
2.第7行这么做的原因是第11行和第12行会先做一次i++和j--,抵消掉这一次移动。
3.第34行和第35行的递归使用一定要格外注意边界值!
4.第7行为数组q中间的元素的值。
2.归并排序
基本思想
分治
基本思路
- 确定分界点,一定是中间下标mid;
- 递归排序左右两个数组;
- 归并——合二为一。
源代码
#include <iostream>
using namespace std;
void mergeSort(int q[], int l ,int r)
{
if(l >= r) return;//数组长度为1则直接返回
int mid = l + r >> 1;//取中间值下标
int tmp[N] = 0;//tmp为辅助数组,存储最终答案,N根据题目而定
mergeSort(q, l, mid);//归并
mergeSort(q, mid+1, r);//归并
int k = 0, i = l, j = mid + 1;
//k指向数组tmp,i指向左边数组第一个元素,j指向右边数组第一个元素
while(i <= mid && j <= r)//遍历数组,i,j其中一个到达最后一个元素时停止
{
if(q[i] <= q[j]) tmp[k++] = q[i++];//将较小者依次放入k
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
q[i] = tmp[j];
}
注意事项
1.第一次调用mergeSort时,q为待排序数组,l为0,r为数组最后一个元素的下标。
2.第13行注意k,i,j的初始值,第15行注意判定条件。
3.第10行和第11行一定要格外注意边界值!
4.第7行为数组中间的下标值。
3.快速选择
基本思想
在快速排序的算法上稍作修改
基本思路
- 同快速排序;
- 递归时只递归答案可能位于的子区间.
源代码
#include <iostream>
using namespace std;
//输入一串数字,求第k小的数
const int N = 1e5 + 10;
int q[N];
int quickSelect(int l, int r, int q[],int k)//直接返回答案
{
if(l>=r) return q[l];
int x = q[(l + r) >> 1];
int i = l-1, j = r+1;
while(i<j)
{
do i++; while(q[i] < x);
do j--; while(q[j] > x);
if(i<j)
swap(q[i], q[j]);
}
if(j - l + 1 >= k) return quickSelect(l, j, q, k);//递归左区间
else return quickSelect(j+1, r, q, k-(j-l+1));//递归右区间
}
int main(void)
{
int n,k;
scanf("%d%d",&n,&k);
for(int i = 0;i < n; i++) scanf("%d", &q[i]);
cout << quickSelect(0,n-1,q,k);//直接打印答案
return 0;
}
注意事项
1.第20行为判断左区间长度是否大于等于k,如果成立,则答案就在左区间。
2.第21行要注意递归右区间时k值的变化。
仅供参考学习。