排序
来源:互联网 发布:佳能mg3580清零软件 编辑:程序博客网 时间:2024/04/29 08:54
分治策略
1. Divide:将大问题分解成若干个小问题;
2. Conquer:递归解决所有子问题;
3. Conbine:合并
T(n) = 2T(n/2) + theta(n); T(n) = θ(nlgn);
二分搜索
1. Divide x与中间值比较
2. Conquer 递归找下一个子数组
3. Conbine 不做动作
T(n) = T(n/2) + θ(1); T(n) = θ(lgn);
x^n
Sol. 1 x*x*x*x...x T(n) = θ(n);
Sol. 2 x^n = x^(n/2) * x^(n/2)T(n) = θ(n);
Fibonacci数列
F(n) = F(n-1) + F(n-2); F(1) = 1, F(0) = 0;
Sol. 1 递归:从n求到1,时间复杂度指数级增长
Sol. 2 Bottom-up求解:从1到n求解,F(1), F(2), ... F(n)时间复杂度:θ(n)
Sol. 3 利用下面的矩阵我就可以实现θ(lgn)的时间复杂度
集成电路完全二叉树布局
正常情况二叉树面积θ(nlogn)
改进后面积θ(n)
矩阵相乘
Sol. 1 用三重循环计算,时间复杂度θ(n^3)
Sol. 2 用分治,包含8个递归,时间复杂度仍然为θ(n^3) T(n) = 8T(n/2) + θ(n^2)
Sol. 3 Strassen算法,通过数学转换将8个递归转换成7个递归,时间复杂度降为θ(n^2.81)
理论上矩阵相乘的时间复杂度可以达到θ(n^2.376)
快速排序
原理与实现
xi j
5 4 8 9 6 3 2 5 7 1
x i j
5 4 8 9 6 3 2 5 7 1
x i j
5 4 8 9 6 3 2 5 7 1
x i j
5 4 8 9 6 3 2 5 7 1
x i j
5 4 8 9 6 3 2 5 7 1
x i j
5 4 3 9 6 8 2 5 7 1
x i j
5 4 3 9 6 8 2 5 7 1
x i j
5 4 3 2 6 8 9 5 7 1
x i j
5 4 3 2 6 8 9 5 7 1
x i j
5 4 3 2 6 8 9 5 7 1
x i j
5 4 3 2 6 8 9 5 7 1
x i j
5 4 3 2 1 8 9 5 7 6
i x j
1 4 3 2 5 8 9 5 7 6
//// 排序代码
Partition(A, p ,q)
r = p; i = p; x = A[p]; // i 指向最后一个小于x的值的序号,j指向当前循环位置
r = p; i = p; x = A[p]; // i 指向最后一个小于x的值的序号,j指向当前循环位置
// 对于随机算法 r = random(p,q);
for j = p+1 to q
if x > A[j]
i++;
exchange(A[i],A[j]);
exchange(A[i],A[p]);
return i;
for j = p+1 to q
if x > A[j]
i++;
exchange(A[i],A[j]);
exchange(A[i],A[p]);
return i;
QickSort(A,p,q)
if p < q
r = Partition(A,p,q)
QickSort(A,p,r);
QickSort(A,r+1,q);
if p < q
r = Partition(A,p,q)
QickSort(A,p,r);
QickSort(A,r+1,q);
// 代码
#include <iostream> #include <string> using namespace std;void exchange(int& a, int& b){int m = a;a = b;b = m;}int Partition(int* A,int& p ,int& q){int r = p; int i = p; int x = A[p]; // i 指向最后一个小于x的值的序号,j指向当前循环位置for(int j = p+1; j <= q; ++j) {if( x > A[j]){i++;exchange(A[i],A[j]);}}exchange(A[i],A[p]);return i;}void QickSort(int* A,int p ,int q){if(p < q) {int r;r = Partition(A,p,q);QickSort(A,p,r-1);QickSort(A,r+1,q);}}int main(){int A[] = {4,5,6,8,3,4,9,7,3,5,8,5,10,15,0,2,36,5,8,12};int len = sizeof(A)/sizeof(int);cout<<"A排序前:";for (int i = 0; i < len; ++i){cout<<A[i]<<" ";}cout<<endl;QickSort(A,0,len-1);cout<<"A排序后:";for (int i = 0; i < len; ++i){cout<<A[i]<<" ";}cout<<endl;}
算法时间复杂度分析
快排相对于归并排序来说时间复杂度最好时是一样的,归并排序是稳定的排序算法,但要求窗外的内存空间,而快排是原址排序,时间复杂度上是不稳定的,除非加入随机算法过程;
最坏的情况:
就是每次递归得到的值都在一边,则此时时间复杂度有 T(n) = T(0) + T(n-1) + θ(n); T(n) = θ(n^2);
一般情况:
取正中间 T(n) = 2T(n/2) + θ(n); T(n) = θ(nlgn);
取其它值:时间复杂T(n) = θ(nlgn);
非随机化版本:
好坏交替出现的情况,其时间复杂度与最好的情况一样,T(n) = θ(nlgn); // 即平均情况
随机化版本:
平均时间复杂度为T(n) = θ(nlgn);
快速排序在应用中是归并排序的3倍快
非比较排序
前面的插入、选择、堆、归并、冒泡、快速排序版本,最好的情况都只能达到T(n) = θ(nlgn);
原因是它们都是通过比较大小的模型 来排序,因此为了达到更快的排序效果,我们可以使用非比较大小的方式来实现;
决策树模型:
树的每一个内节点有下标:i:j
对于a1,a2,...an;比较ai与aj,如果ai<=aj,左子树;否则右子树
最终每个叶节点代表一种排序
计数排序
对于n个输入元素中每个数在0~k之间,如果k=O(n),则排序时间为T(n) = θ(n); // 即一般如果数的个数多但范围有限且相对n较小,则可以用计数排序。
// 伪代码 n为数组长度,k为最大数,则里面的数组C长度应该为k+1(0~k)
CountSort(A,n,k)for i = 0 to kC[i] = 0;for j = 0 to n-1C[A[j]]++; // C[i]表示了值为i的个数for i = 1 to kC[i] += C[i-1]; // 对于当前位i的值C[i]表示了至少有C[i]个数小于等于i// 排序for i = n-1 to 0B[C[A[i]]] = A[i];C[A[i]]--;
// 代码
int* CountSort(int* A,const int n,const int k){int *C = new int[k+1](); // k+1长度,初始化为0int *B = new int[n]();for(int j = 0; j < n; ++j)C[A[j]]++; // C[i]表示了值为i的个数for(int t = 1; t <= k+1; ++t)C[t] += C[t-1]; // 对于当前位i的值C[i]表示了至少有C[i]个数小于等于i// 排序for(int m = 0; m < n; ++m){B[C[A[m]]] = A[m];C[A[m]]--;}//delete[] C; // delete会崩溃return B;}
基数排序
桶排序
0 0
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 排序
- 一个panic bug的分析过程(一)
- 关于C++中虚函数表的几点总结
- SAX解析学习总结
- android SharedPreferences保存数据
- Search in Rotated Sorted Array
- 排序
- BZOJ 1642: [Usaco2007 Nov]Milking Time 挤奶时间
- 模拟水题。。。
- linux(ubuntu)下安装eclipse
- Twitter Storm源代码分析之acker工作流程
- 组合数
- RabbitMQ学习(二).NET Client之Work Queues
- hdu 2066
- UI 捏合手势