第二章上机实验报告

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;
}

                     

posted @ 2020-10-03 23:56  cineny  阅读(181)  评论(0)    收藏  举报