实验二 典型排序算法训练:快速排序、计数排序

算法导论实验二


前言

算法导论实验二 典型排序算法训练:快速排序、计数排序


`

一、实验原理

1.1 快速排序原理

快速排序的思想是任找一个元素作为基准,对待排数组进行分组,使基准元素左边的数据都比基准数据要小,右边的数据都比基准数据要大,这样基准元素就放在了正确的位置上。然后对基准元素左边和右边的组进行相同的操作,最后将数据排序完成。
在这里插入图片描述

1.2 计数排序原理

计数排序是由额外空间的辅助和元素本身的值决定的。计数排序过程中不存在元素之间的比较和交换操作,根据元素本身的值,将每个元素出现的次数记录到辅助空间后,通过对辅助空间内数据的计算,即可确定每一个元素最终的位置。
算法过程:

  1. 根据待排序集合中最大元素和最小元素的差值范围,申请额外空间
  2. 遍历待排序集合,将每个元素出现的次数记录到元素值对应的额外空间内。
  3. 对额外空间内数据进行计算,得出每一个元素的正确位置。
  4. 将待排序集合每一个元素移动到计算出的正确位置上。
    在这里插入图片描述

计数排序的一个重要性质就是它是稳定的:具有相同值的元素在输出数组中的相对次序与它们在输入数组中的次序相同,即在输入数组中先出现的,在输出数组中也位于前面

二、实验要求

2.1 实现对数组[-2,1,-3,4,-1,2,1,-5,4]的快速排序并画出流程图。

根据快速排序分治算法原理,c++代码如下所示:

#include <iostream>
#include <vector>
using namespace std;
int partition(vector<int>& nums,int left,int right);
void quickSort(vector<int>& nums,int left,int right){
    if(left < right){
        int jizhunIndex = partition(nums,left,right);
        quickSort(nums,left,jizhunIndex - 1);
        quickSort(nums,jizhunIndex + 1,right);
    }
}

int partition(vector<int>& nums,int left,int right){
    int jizhun = nums[right];
    int i = left - 1;
    for(int j = left;j < right;j++){
        if(nums[j] <= jizhun){
            swap(nums[++i],nums[j]);
        }
    }
    swap(nums[++i],nums[right]);
    return i;
}

int main(){
    vector<int> nums = {-2,1,-3,4,-1,2,1,-5,4};
    quickSort(nums,0,nums.size() - 1);
    for(int num :nums){
        cout << num << " ";
    }
    return 0;
}

程序输出如下图所示:
快速排序运行结果
流程图如下所示:
在这里插入图片描述
在这里插入图片描述

2.2 实现对数组[95, 94, 91, 98, 99, 90, 99, 93, 91, 92]的计数排序并画出流程图

根据计数排序的思想,c++代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int subNum = 0;
vector<int> countSort(vector<int>& inputArray,int k);
int main(){
    vector<int> array = {95,94,91,98,99,90,99,93,91,92};
    subNum = *min_element(array.begin(),array.end());
    subNum = 90;
    vector<int> resArray = countSort(array,*max_element(array.begin(),array.end()) - subNum + 1);
    for(int num : resArray){
        cout << num << " ";
    } 
    return 0;
}
vector<int> countSort(vector<int>& inputArray,int k){
    vector<int> tempArray(k,0);
    vector<int> outputArray(inputArray.size(),0);
    for(int i = 0;i < inputArray.size();i++){
        tempArray[inputArray[i] - subNum]++;
    }
    for(int i = 1;i < k;i++){
        tempArray[i] += tempArray[i - 1];
    }
    for(int i = inputArray.size() - 1;i >= 0;i--){
        outputArray[tempArray[inputArray[i] - subNum] - 1] = inputArray[i];
        tempArray[inputArray[i] - subNum]--;
    }
    return outputArray;
}

程序输出如下图所示:
计数排序程序输出
计数排序流程图如下所示:
在这里插入图片描述

2.3 以上两种排序算法的区别有哪些?分别的时间和空间复杂度是多少?

快速排序是基于分治算法,每次确定一个基准元素的位置,通过元素之间的比较和交换来实现,会出现值相同元素次序的变化,即该排序算法是不稳定的。时间复杂度O(nlogn),空间复杂度O(logn)。
而计数排序是稳定的,根据元素的大小次序使用计数数组计数,从而把元素根据计数数组放到相应的位置上,但不好的地方在于如果最大和最小元素的差值比较大,会造成较大的空间损耗(计数数组)。时间复杂度O(n),空间复杂度O(k)k为数组中最大值减去最小值


总结

主要就是对常见的排序算法快速排序和计数排序进行一个实践,并画出流程图分析其时间和空间复杂度,让我对于排序算法有了更加深刻的了解。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值