1、组内有个分享的活动,我整理了常用的排序算法。讲的不太通,备份下,会陆续把代码附上。
内部排序:
例子中都是从小到大排序的。
1、 插入排序
1.1、 直接插入排序:将一个记录插入到一个有序的列表中,得到一个新的,记录数加一的新的列表。进行关键字比较和移动的次数约N^2/4,时间复杂度O(N^2)。
1.2、 折半插入排序:在直接插入排序的基础上减少比较的次数。其中“查找”的动作用“折半查找”来实现。只能减少比较的次数,不能减少移动的次数,时间复杂度O(N^2)。N较大的时候效果明显。
1.3、 2-路插入排序:在折半插入排序上再改进,减少移动的次数。需要N个辅助空间,如a[N],从小到大排序,将第一个数放在a[0]中,如果比a[0]大,放在后面,如果比a[0]小,放在前面。将数组a[]看成一个循环向量。移动的次数约为N^2/8.时间复杂度O(N^2)。如果a[0]是最小的话,就失效了。
1.4、 希尔排序:主要是通过增量序列中5和3,把整个序列弄的基本有序。以减少排序的比较和移动的次数。【如何取增量序列,和如何计算时间复杂度没有定论】
2、 快速排序
2.1、 起泡排序:每次比较后,将待排序的数中最大的那个放到最后。比较和移动的次数为N*(N-1)/2。时间复杂度O(N^2)。
2.2、 快速排序:对起泡排序进行改进,每趟排序,将待排记录中提取一个关键字,将其分成两块,一块都比这个关键字小,一块都比这个关键字大。递归下去,直到结束。时间复杂度O(N*logN)。注意栈的深度。
非递归的版本:URL:http://blog.163.com/liyilouis007@126/blog/static/31809050201146113859317/
#include <iostream>
#include <stack>
using namespace std;
template <class T>
int partition(T a[],int low,int high)
{
T v=a[low];
while(low<high)
{
while(low<high && a[high]>=v)
high--;
a[low]=a[high];
while(low<high && a[low]<=v)
low++;
a[high]=a[low];
}
a[low]=v;
return low;
}
template <class T>
void QuickSort(T a[],int p,int q)
{
stack<int> st;
int j;
do{
while(p<q)
{
j=partition(a,p,q);
if( (j-p)<(q-j) )
{
st.push(j+1);
st.push(q);
q=j-1;
}
else
{
st.push(p);
st.push(j-1);
p=j+1;
}
}
if(st.empty())
return;
q=st.top();st.pop();
p=st.top();st.pop();
}while(1);
}
int main()
{
int a[7]={3,5,2,3,1,66,225};
for(int i=0;i<7;i++)
cout<<a[i]<<" ";
cout<<endl;
QuickSort(a,0,6);
for(int i=0;i<7;i++)
cout<<a[i]<<" ";
return 0;
}
3、 选择排序
3.1、简单选择排序:每一趟在N-i+1(I = 1,2….N)中找到最小的作为有序序列的第i个记录。 关键字间比较的次数为N(N-1)/2.时间复杂度为O(N^2)。
3.2、树形选择排序:改进的方向是减少比较次数,是因为前一次的比较对后面也是有意 义的。从体育比赛锦标赛中引申而来。时间复杂度为。
3.3、堆形选择排序:
n个关键字序列Kl,K2,…,Kn称为(Heap),当且仅当该序列满足如下性质(简称 为堆性质):(1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),当然,这是小根堆,大根堆 则换成>=号。//k(i)相当于二叉树的非叶结点,K(2i)则是左孩子,k(2i+1)是右孩 子完全二叉树。得到最小的值,然后调整剩下的元素,让其满足堆的性质,继续取出最小值。知道堆中只剩下一个元素为止。适用于较多的数。时间复杂度为:O(N*logN)。
对应的代码:
#include <map>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <iostream>
using namespace std;
int NUM = 19;
int a[19] ={0,1,2,3,4,5,6,7,8,0,1,2,3,4,5,6,7,8,0};
//int i代表开始的位置,lenth总的长度
void heapsort(int a[],int i,int lenth)
{
cout<<"i is "<<i<<" lenth is "<<lenth<<" "<<endl;
int tmp = a[i], child = 2*i;
for (; child <= lenth; child *= 2)
{
if ((child + 1 <= lenth ) && (a[child] < a[child+1]))
++child;
if (tmp > a[child])
break;
a[i] = a[child];
i = child;
}
a[i] = tmp;
}
int main()
{
int t,tmp;
int i;
for(i = 0; i < NUM; i++)
cout<<a[i]<<" ";
cout<<endl;
for (t = NUM/2; t > 0; t--)
{
heapsort(a,t,NUM - 1);
for(i = 0; i < NUM; i++)
cout<<a[i]<<" ";
cout<<endl;
}
cout<<"--------------"<<endl;
for (t = NUM - 1; t > 1; t--)
{
tmp = a[1]; a[1]=a[t]; a[t]=tmp;
heapsort(a,1,t-1);
for(i = 0; i < NUM; i++)
cout<<a[i]<<" ";
cout<<endl;
}
}
4、 计数排序: 每次扫描所有的数,将比要排序的数小的数的个数记下来,然后将这个要排序的数放在个数+1的位置。
5、 基数排序:将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。基数排序的时间复杂度是O(k·n),其中n是排序元素个数,k是数字位数。
6、 桶排序:假定:输入是由一个随机过程产生的[0, 1)区间上均匀分布的实数。将区间[0, 1)划分为n个大小相等的子区间(桶),每桶大小1/n:[0, 1/n), [1/n, 2/n), [2/n, 3/n),…,[k/n, (k+1)/n ),…将n个输入元素分配到这些桶中,对桶中元素进行排序,然后依次连接桶输入0 ≤A[1..n] <1辅助数组B[0..n-1]是一指针数组,指向桶(链表)。
7、归并排序:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表。SR[1,2,3,…n],SR中为n个前后相邻且长度为h的有序序列。时间复杂度为,空间O(n)。其中n是指序列的个数。
外部排序
利用外存对数据文件进行排序的方法称为外部排序。
1、 简单归并排序。