第二章上机实验报告
1.实验名称:寻找找第k小的数
2.问题描述:
a.题目大意:在n个无序的整数中找出第k小的数-------快速排序
b.题目要求:平均时间为O(n)------优化快速排序
3.算法描述:
a.核心函数:int partition(int a[],int left,int right)可以根据a[left]~a[right]中的左端元素x进行划分,交换x左右的元素,使得x左边元素均小于x,右边元素均大于x,从而继续分化
int partition(int a[], int left, int right)
{
int x = a[left]; //使左端元素x为划分依据
while(left < right)
{
while (left < right && a[right] >= x) right--; //从右端开始下标左移,若大于x则不改变位置
a[left] = a[right]; //大于x的元素移到最左端
while (left < right && a[left] <= x) left++; //从左端开始下标右移,若小于x则不改变位置
a[right] = a[left]; //小于x的元素移到最右端
}
a[left] = x; //使中间元素等于x
return left; //返回x的下标
}
b.判断第k小:int find(int a[],int left,int right,int k)可以利用x所在的位置计算出x是这批数据按升非降序排列的第几个数,判断划分点是否第k小
若不是,递归调用find函数继续在左段或右段查找
int find(int a[], int left, int right, int k)
{
int pos = partition(a, left, right); //利用partition函数找出中间元素x的下标
if (k - 1 == pos) cout << a[k - 1]; //如果是第k小数,则直接输出
else if (k - 1 < pos) find(a, left, pos - 1, k); //如果是第0~k-1小的数则在左区间查找
else find(a, pos + 1, right, k);
return 0;
}
c.优化函数:int random_partitionint a[],int left,int right)随机划分使得期望划分对称,避免最坏情况
最坏情况:partition函数每次均出现两个区域元素个数为n-1和1这种极端不对称情况,时间复杂度为O(n^2)
int random_partition(int a[],int left,int right)
{
int i=(rand() % (right-left+1))+ left; //取left和right之间的随机某数作为中间元素x
swap(a[i],a[left]);
return partition(a,left,right);
}
void quick_sort(int a[],int left,int right)
{
if(left<right)
{
int k = random_partition(a,left,right);
quick_sort(a,left,k-1);
quick_sort(a,k+1,right);
}
}
4.算法分析
a.时间复杂度:O(nlogn)
①分解子问题:以中间元素x为基准分成三段------O(n)
②递归求解:T(n)=2T(n/2)+O(n)
b.空间复杂度:数组存储------O(n)
5.心得体会
快速排序是利用分治法策略的优秀算法,对我来说其中有两个难点:
①理解partition函数的作用:通过不断进行以中间元素x为依据的划分,使得数组的有序程度步步提升
②理解quick_sort对partition的调用:每段开头返回中间元素位置,以此分成两边,两边再次调用partition进行递归分治
完整代码:
#include <iostream>
using namespace std;
int partition(int a[], int left, int right)
{
int x = a[left];
int i = left;
int j = right;
while(i < j)
{
while (i < j && a[j] >= x) j--;
while (i < j && a[i] <= x) i++;
swap(a[i],a[j]);
}
a[i] = x;
return i;
}
int find(int a[], int left, int right, int k)
{
int pos = partition(a, left, right);
if (k - 1 == pos) cout << a[k - 1];
else if (k - 1 < pos) find(a, left, pos - 1, k);
else find(a, pos + 1, right, k);
return 0;
}
int main()
{
int n, k;
cin >> n >> k;
int a[1000];
for (int i = 0; i < n; i++) cin >> a[i];
find(a, 0, n - 1, k);
return 0;
}

浙公网安备 33010602011771号