您的位置:首页 > 其它

算法导论 第二部分——排序和顺序统计量

2016-07-07 15:18 302 查看
一、堆排序 : 原址排序 复杂度: nlg n

最大堆: A[parent(i)] > = A[i]

最小堆: A[parent(i)] < = A[i]

除了最底层外,其它层都是满状态。

判断节点是否为叶节点: [n/2]+1,.....n 均为叶节点

//Max-heapify(A,i)   : A为一个 假定 left(i) right(i)的二叉树都是最大堆 。 但是A[i]可能小于孩子  。 时间复杂度为: o(h)
//build_max_heap(A,len) : 将一个数组转换为 最大堆(从底向上的建堆) , 时间复杂度为: o(n)
//heap_sort(A,len)      : 将 A 进行排序  复杂度 为 nlg(n)
void max_heapify(int *A , int i,int len)
{
int r = RIGHT(i);
int l = LEFT(i);
int large = i;
if (i <= len&&*(A + i-1) < *(A+r-1))
large = r;
if (i <= len && *(A+large-1)<*(A+l-1))
large = l;
if (large == i)
return;
else
swap(A, large-1, i-1,len);
if (i <= len && 2 * i < len/2+1)    // decide if  the left son node is leaf node
max_heapify(A, large, len);     // not leaf node , carry on the recursion
else
return;                            // end the recursion
}

void build_max_heap(int *A, int len)
{
for (int i = len / 2; i>0; i--)
max_heapify(A,i,len);
}

void heap_sort(int *A, int len)
{
build_max_heap(A,len);
for (int i = len; i > 0; i--)
{
swap(A, i - 1, 0 ,len);
max_heapify(A,1,i);
}
}


二、快速排序 原址

最坏时间复杂度: n^2 ,但是是实际应用中最好的排序算法,期望时间复杂度:nlgn,而且隐藏的因子特别小。

// partition();     将数组A[p,……,r] 分成 A[p,….,q-1]<=A[q]<=A[q+1,r],返回q的数组下标
// quick_sort() :   递归调用,将分割好的数组继续分割
int  PARTITION(int *A ,int p , int r ,int len)
{
if (p >= len || r >= len|| p<0||r<=0)
{
cout << "function PARTITION erro : the p or r is out range of the vector or array" << endl;
return 0;
}
int i = p - 1;
int x = 0;
for (int j = p; j < r; j++)
{
if (*(A+j)<*(A+r))
{
i = i + 1;
EXCHANGE(A,i,j,len);
}
}
EXCHANGE(A,r,i+1,len);
return i + 1;
}
void QUICK_SORT(int *A,int p,int r,int len)
{
if (p >= r)
{
cout << "function QUICK_SORT error : r must larger than p" << endl;
return;
}
if (p >= len || r >= len||p<0||r<=0)
{
cout << "function QUICK_SORT error : the p or r is out range of the vector or array" << endl;
return;
}
if (p == r)
{
cout << "end of calling of QUICK_SORT" << endl;
return;
}
int mid=PARTITION(A,p,r,len);
cout << "mid is :" << mid << "    p ="<<p<<"    r="<<r<<"    len="<<len<<endl;
QUICK_SORT(A,p,mid-1,len);
QUICK_SORT(A,mid+1,r,len);
output(A,len);
}


performance:

  worst situation:

    T(n) = T(n-1) + k; 它的复杂度为 n^2 ,当数组已经是排好序的,那么他需要进行 n^2 次运算

  best situation:

    T(n) = 2T(n/2)+k; 当两个子问题的规模都不大于n/2,这时候快速排序的性能最好 nlg n次运算

平衡的划分:

  只要每次划分是一种常数比例的划分,都会产生深度为lgn的递归树

  例如: T(n) = T(n/10)+T(9n/10) + k;

quicksort using random function

RANDOMIZED-PARTITION(A, p, r):
i = RANDOM(p, r )
exchange A[r ] ↔ A[i ]
return PARTITION(A, p, r )


三、线性时间排序

1、 决策树模型:

  每次比较判断可以影响下一次的比较,

定理:对于一个比较排序算法在最坏情况下,都需要做Ω(nlgn)次比较。

参考: http://www.cnblogs.com/Anker/archive/2013/01/25/2876397.html
2、计数排序 : 时间复杂度为n ,其实是max-min+1,需要额外开辟内存空间

前提条件: 所有的元素都必须在一个范围内,如: min<a[i]<=max

int * count_sort(int *a ,int n){
//initialize
int max=0xffffffff, min=0x7fffffff;
for (int i = 0; i < n; i++){
if (*(a + i)>max)
max = *(a+i);
if (*(a + i) < min)
min = *(a + i);
}
const int len = max - min+1;
int *c = new int[len];
int *re = new int
;
memset(c,0,len*4);

//count the number of every element in a[] then store in c[]
for (int i = 0; i < n; i++){
*(c + *(a+i) - min) += 1;
}
//sort based c[]
for (int i = 0,j=0; i < len; i++){
int k = 0;
while (k < *(c + i)){
*(re + j) = min + i;
j++;
k++;
}
}
delete []c;
return re;
}


四:中位数和顺序统计量

1、期望为线性时间的选择算法: 最坏时间为n^2

RANDOMIZED_SELECT(A,p,r,i)
if p==r
then return A[p]
//通过partition函数产生q值,与快速排序的partition原理相同
q = RANDOMIZED_PARTITION(A,p,r)
k = q-p+1;
if i==k
then return A[q]
else  if i<k
then return RANDOMIZED_SELECT(A,p,q-1,i)
else
return RANDOMIZED_SELECT(A,p,q-1,i-k)


c++代码:

#include <stdio.h>
#include <stdlib.h>

int partition(int* datas,int beg,int last,int mid);
int select(int* datas,int length,int i);
void swap(int* a,int *b);

int main()
{
int datas[12]={32,23,12,67,45,78,10,39,9,58,125,84};
int i,ret;
printf("The array is: \n");
for(i=0;i<12;++i)
printf("%d ",datas[i]);
printf("\n");
for(i=1;i<=12;++i)
{
ret=select(datas,12,i);
printf("The %dth least number is: %d \n",i,datas[i-1]);
}
exit(0);
}

int partition(int* datas,int beg,int last,int mid)
{
int i,j;
swap(datas+mid,datas+last);
i=beg;
for(j=beg;j<last;j++)
{
if(datas[j] < datas[last])
{
swap(datas+i,datas+j);
i++;
}
}
swap(datas+i,datas+last);
return i;
}

int select(int* datas,int length,int i)
{
int groups,pivot;
int j,k,t,q,beg,glen;
int mid;
int temp,index;
int *pmid;
if(length == 1)
return datas[length-1];
if(length % 5 == 0)
groups = length/5;
else
groups = length/5 +1;
pmid = (int*)malloc(sizeof(int)*groups);
index = 0;
for(j=0;j<groups;j++)
{
beg = j*5;
glen = beg+5;
for(t=beg+1;t<glen && t<length;t++)
{
temp = datas[t];
for(q=t-1;q>=beg && datas[q] > datas[q+1];q--)
swap(datas+q,datas+q+1);
swap(datas+q+1,&temp);
}
glen = glen < length ? glen : length;
pmid[index++] = beg+(glen-beg)/2;
}
for(t=1;t<groups;t++)
{
temp = pmid[t];
for(q=t-1;q>=0 && datas[pmid[q]] > datas[pmid[q+1]];q--)
swap(pmid+q,pmid+q+1);
swap(pmid+q+1,&temp);
}
//printf("mid indx = %d,mid value=%d\n",pmid[groups/2],datas[pmid[groups/2]]);
mid = pmid[groups/2];
pivot = partition(datas,0,length-1,mid);
//printf("pivot=%d,value=%d\n",pivot,datas[pivot]);
k = pivot+1;
if(k == i)
return datas[pivot];
else if(k < i)
return select(datas+k,length-k,i-k);
else
return select(datas,pivot,i);

}

void swap(int* a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: