算法导论——第五章——线性时间排序

本文深入探讨了决策树模型、计数排序、基数排序及桶排序等排序算法的基本原理和实现细节,通过具体实例展示了各种排序算法的工作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

1.决策树模型

比较排序的过程可以被抽象地视为决策树。一棵决策树是一棵满二叉树,表示某排序算法作用于给定输入所做的所有比较。排序算法的执行对应于遍历一条从树的根到叶节点的路径。每个内结点对应一个比较ai&aj,左子树决定着ai<=aj以后的比较,右子树决定着ai>aj以后的比较。当到达一个叶节点时,排序算法就已确定。排序算法能够正确工作的的必要条件是,n个元素的n!种排列都要作为决策树的一个叶节点出现。设决策树的高度为h,叶子数目为l,那么有 2h>=l>=n!,于是有 h>lgn! = Ω(nlgn)。 这说明比较排序的最坏时间复杂度为Ω(nlgn)。这也说明合并排序和堆排序的复杂度已经渐进最优了。

2.计数排序

假设n个输入元素的每一个都是介于0到k之间的整数,此处k为某个整数。当k=O(n)时,计数排序的运行时间为Θ(n)。 计数排序的思想就是对每一个输入元素x,确定出小于x的元素个数。有了这一信息,就可以把x直接放到最终输出数组的位置上。

假定输入是数组A[1...n], 存放排序结果的B[1...n],以及提供计数临时存储的C[0...k]。

COUNTING-SORT(A,B,k)jk

   for  i<- 0 to k

       do C[i] i<- 0 //初始化临时存储数组

   for j i<-1 to length[A]

       do C[A[j]] =C[A[j]]+1

//到此时C[i]中数值表示A中等于i的元素个数

   for i <-1 to k

       do C[i] = C[i] + C[i-1]

//到此时C[i]中数值表示A中等于小鱼等于i的元素个数

   for i <- length[A] downto 1

       do B[C[A[i]] = A[i]

            C[A[i]] = C[A[i]] -1  //important

第七行,从length[A] downto 1是为了正确解决由相同元素时的排序情况,保证算法稳定。若改为for i<- 1 upto length[A],则排序不稳定。


05 #include <vector>
06 #include <iostream>
07 using namespace std;
08 //此程序是实现计数排序算法,要特别注意指标问题
10 void counting_sort(vector<int> A, vector<int>& B, int k);
11 int main()
12 {
13     int a[]={1,4,3,2,0,4,3,5,7,5,4,6,7,8,5,9,6,4,3,4,0};
14     int k=9;
15     vector<int> A(a,a+20);
16     vector<int> B(20,0);
17     counting_sort(A, B, k);
18     vector<int>::iterator i;
19     for(i=B.begin();i!=B.end();i++)
20         cout<<*i<< ";
21     return 0;
22 }
23   
24 void counting_sort(vector<int> A, vector<int>& B, int k)
25 {
26     vector<int> C(k+1,0);
27     //统计A中重复元素的个数,C的指标表示这个元素的值,C的值表示对应元素的个数
28     for(int j=0;j<A.size();j++)
29         C[A[j]]=C[A[j]]+1;
30     //统计这个值在数组中的放置的位置,即排在第几位
31     for(int i=1;i<=k;i++)
32         C[i]=C[i]+C[i-1];
33     //一次将A中的每个元素放到正确的位置,计入数组下标应从0开始,因此用C[A[j]]减去1
34     for(int j=A.size()-1;j>=0;j--)
35     {
36         B[C[A[j]]-1]=A[j];
37         C[A[j]]=C[A[j]]-1;
38     }
39 }

3.基数排序

基本思想:按组成关键字的各个位的值来实现排序的

基数:计算的基数就是基本的单元数。比如10进制的基数就是10,二进制的基数就2,八进制的基数是8等等。

基数排序说通俗点,就是把带排序的N个数字右对齐排成一列。然后把相同的位数互相比较,来排序

 6 #include <iostream>
 7 #include <cstring>
 8 using namespace std;
 9  
10 int arr[100], res[100], hash[10];
11 int n;
12  
13 int maxbit()
14 {
15        int _max = 0;
16        int temp[100];
17        for(int i=0i<n; ++i)
18            temp[i] = arr[i];
19  
20        for (int i=0i<n; ++i)
21        {
22               int tt = 1;
23               while(temp[i]/10 > 0)
24               {
25                      tt++;
26                      temp[i] /= 10;
27               }
28               if(_max < tt)
29                      _max = tt;
30        }
31        cout << "_max " << _max << endl;
32        return _max;
33 }
34  
35 void radixSort()
36 {
37     memset(res, 0sizeof(res));
38     int nbit = maxbit();
39     int tmp;
40     int radix = 1;
41     // 以下和计数排序一样
42     for(int i=1i<=nbit; ++i)
43     {
44         for(int j=0j<10++j)
45             hash[j] = 0;
46         for(int j=0j<n; ++j)
47         {
48             tmp = (arr[j]/radix)%10;
49             ++hash[tmp];
50         }
51         for(int j=1j<10++j)
52             hash[j] += hash[j-1];
53         for(int j=n-1j>=0--j)
54         {
55             tmp = (arr[j]/radix)%10;
56             --hash[tmp];
57             res[hash[tmp]] = arr[j];
58         }
59         for(int j=0j<n; ++j)
60             arr[j] = res[j];
61         radix *= 10;
62     }
63 }
64  
65 int main()
66 {
67     freopen("input.txt""r"stdin);
68     cout << "输入元素个数: ";
69     cin >> n;
70     cout << "输入" << << "个元素: " << endl;
71     for(int i=0i<n; ++i)
72         cin >> arr[i];
73     radixSort();
74     cout << "排序后结果为: " << endl;
75     for(int i=0i<n; ++i)
76         cout << res[i] << " ";
77     cout << endl;
78 }
4.桶排序(期望时间复杂度O(n))

桶排序算法想法类似于散列表

首先要假设待排序的元素输入符合某种均匀分布,例如数据均匀分布在[ 0,1)区间上.

则可将此区间划分为10个小区间,称为桶,每个桶存放一个链表,对散布到同一个桶

中的元素在排序。

01 // bucketsort.cpp : 定义控制台应用程序的入口点。
02 // 桶排序算法,要用到前面的堆排序算法进行桶内的排序
03 //肖成 2011/3/28
04 #include "vectorheap.h"
05 #include <iostream>
06 #include <list>
07 #include <algorithm>
08 #include <cstdlib>
09 using namespace std;
10   
11 vector<vector<double>> bucket_sort(vector<double> vec);
12   
13 int main()
14 {
15     double a[]={0.34,0.21,0.41,0.11,0.32,0.42,0.22,0.51,0.62,0.71};
16   
17     vector<double> vec(a,a+10);
18     vector<vector<double>> lstvec;
19   
20     lstvec=bucket_sort(vec);
21     vector<double>::iterator vecIter;
22     vector<vector<double>>::iterator lstIter;
23       
24     for(lstIter=lstvec.begin(); lstIter!=lstvec.end();lstIter++)
25     {
26         for(vecIter=(*lstIter).begin();vecIter!=(*lstIter).end();vecIter++)
27             cout<<*vecIter<< ";
28     }
29     cout<<endl;
30     return 0;
31 }
32   
33 //从大到小排序
34 vector<vector<double>> bucket_sort(vector<double> vec)
35 {
36     int n=vec.size();
37     vector<vector<double>> lst(n);
38     vector<vector<double>>::iterator iter;
39   
40     //计算散布到桶的位置,因为是从大到小所以要倒序散布
41     for(int i=0;i<n;i++)
42         lst.at((int)(n-n*vec.at(i))).push_back(vec.at(i));
43       
44     for(int i=n-1; i>=0; i--)
45     {
46         //对桶内的元素进行堆排序
47         vectorheap<double> vecheap(lst.at(i));
48         lst.at(i)=vecheap.sortHeap();
49     }
50     return lst;
51 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值