算法导论:排序

时间:2021-04-08 19:05:00

 
算法导论*讲了五种排序,分别是插入排序,归并排序,堆排序,快速排序和计数排序。 

(1)插入排序

插入排序的最坏情况运行时间为θ(n^2),但其算法的内循环是紧密的,对于小规模输入来说是一个快速的原地排序算法

伪代码如下:

Insertion sort
Insertion sort(A,n) //sort A[1,..n]
for j←2 to n
    do key←A[j]
       i←j-1	
       while i>0 and A[i]>key
             do A[i+1]←A[i]
   		i←i-1
       A[i+1]←key

 c语言程序代码如下:

void insertion(int aa[],int n)
{
	int key,i;
        for(int j=2;j<=n;j++)
	{
		key=aa[j];
		i=j-1;
		while(i>0&&aa[i]>key)
		{
			aa[i+1]=aa[i];
			i--;
		}
		aa[i+1]=key;
	}
}

(2)归并排序

归并排序有着较好的渐进运行时间θ(nlgn),但其中的MERGE程序不在原地操作

伪代码如下:

MERGE(A,p,q,r)
n1←q-p+1
n2←r-q
create arrays L[1...n1+1] and R[1...n2+1]
for i←1 to n1
	do L[i]←A[p+i-1]
for j←1 to n2
	do R[j]←A[q+j]
L[n1+1]←∞
R[n2+1]←∞
i←1
j←1
for k←p to r
	do if L[i]<=R[j]
	   then A[k]←L[i]
		i←i+1
	   else A[k]←R[j]
		j←j+1
MERGE-SORT(A,p,r)
if p<r
then q←(p+r)/2
MERGE_SORT(A,p,q)
MERGE-SORT(A,q+1,r)
MERGE(A,p,q,r)

c语言代码如下:

void merge(int a[],int p,int q,int r)
{
	int n1=0,n2=0;
	n1=q-p+1;
	n2=r-q;
	int *L=new int[n1+1];
	int *R=new int[n2+1];
	for(int i=0;i<n1;i++)
		L[i]=a[p+i];
	for(int j=0;j<n2;j++)
		R[j]=a[q+j+1];
	i=0;
	j=0;
	L[n1]=2147483647;
	R[n2]=2147483647;
	for(int k=p;k<=r;k++)
	{
		if(L[i]<=R[j])
		{
			a[k]=L[i];
			i++;
		}
		else
		{
			a[k]=R[j];
			j++;
		}
	}
	delete[] L;
	delete[] R;
}
void mergesort(int a[],int p,int r)
{
	if( p<r)
	{
		int q=(p+r)/2;
		mergesort(a,p,q);
		mergesort(a,q+1,r);
		merge(a,p,q,r);
	}
}


(3)堆排序

堆排序要用到叫堆的数据结构,它可以在O(nlgn)时间内对n个数进行原地排序。

伪代码如下

表示堆的数组A是一个具有两个属性的对象:length[A]是数组中数组中的元素个数,heap-size[A]是存放在A中的堆的元素的元素个数,就是说,虽然A[1...length[A]]中都可以包含有效值,但A[heap-size[A]]之后的元素都不属于相应的堆,此处heap-size[A]<=length[A]。树的根为A[1],但定了某个节点的下标i,其父节点PARENT(i),左儿子LEFT(i)和右儿子RIGHT(i)的下标都可以简单的计算出来

伪代码如下:

MAX_HEAPIFY(A,i)
l←LEFT(i)
r←RIGHT(i)
if l<=heap-size[A] and A[l]>A[i]
   then largest←l
   else largest←r
if r<=heap-size[A] and A[r]>A[largest]
   then largest←r
if largest!=i
   then exchange A[i]←→A[;argest]
MAX-HEAPIFY(A,largest)

BUILD-MAX-HEAP(A)
heap-size[A]←length[A]
for i←length[A]/2 downto 1
    do MAX-HEAPIFY(A,i)

HEAPSORT(A)
BUILD-MAX-HEAP(A)
for i←length[A] downto 2
    do exchange A[1]←→A[i]
       heap-size[A]←heap-size[A]-1
       MAX-HEAPIFY(A,1)


c语言代码如下:

int heapsize;
void maxheapify(int a[],int i)
{
	int l=0,r=0,largest=0,ex=0;
	l=2*i+1,r=2*i+2;
	if(a[l]>a[i]&&l<=heapsize)
	   largest=l;
	else
	   largest=i;
	if (r<=heapsize&&a[r]>a[largest])
 	       largest=r;
	if (largest!=i)
	{
	  ex=a[i];
	  a[i]=a[largest];
	  a[largest]=ex;
	  maxheapify(a,largest);
	}
}
void buildmaxheap(int a[],int n)
{
	heapsize=n-1;
	for(int t=(n/2-1);t>=0;t--)
	    maxheapify(a,t);
}
void heapsort(int a[],int q)
{
	int change=0;
	buildmaxheap(a,q);
	for(int j=q-1;j>=1;j--)
	{
	    change=a[0];
	    a[0]=a[j];
	    a[j]=change;
	    heapsize--;
	    maxheapify(a,0);
	}
}


(4)快速排序

快速排序是一种对n个数进行原地排序的算法,但是他的最坏情况运行时间为θ(n^2).他的平均运行时间是θ(n*lgn)

伪代码如下:

QUICKSORT(A,p,r)
if p<r
then q←PARTITION(A,p,r)
       QUICKSORT(A,r,q-1)
       QUICKSORT(A,p+1,r)

PARTITION(A,p,r)
x←A[r]
i←p-1
for j←p to r-1
    do if A[j]<=x
          then i←i+1
	       exchange A[i]←→A[j]
exchange A[i+1]←→A[r]
return i+1

c语言代码如下:

int partition(int a[],int p,int r)
{
	int i=p-1;
	int x=a[r];
	int ex1=0,ex2=0;
	for(int j=p;j<r;j++)
	{
		if(a[j]<=x)
		{
			i++;
			ex1=a[i];
			a[i]=a[j];
			a[j]=ex1;
		}
	}
	ex2=a[i+1];
	a[i+1]=a[r];
	a[r]=ex2;
	return i+1;

}
void quicksort(int a[],int p,int r)
{
	int q=0;
	if(p<r)
	{
		q=partition(a,p,r);
		quicksort(a,p,q-1);
		quicksort(a,q+1,r);
	}
}


快速排序的随机化伪代码如下:

RANDOMIZED-PARTITION(A,p,r)
i←RANDOM(p,r)
exchange A[i]←→A[r]
reuturn PARTITION(A,p,r)

RANDOMIZED-QUICKSORT(A.p,r)
if p<r
then q←RANDOMZIED-PARTITION(A,p,r)
 RANDOMZIED-PARTITION(A,p,q-1)
 RANDOMZIED-PARTITION(A,q+1,r)


c语言代码如下
int partition(int a[],int p,int r)
{
	int i=p-1;
	int x=a[r];
	int ex1=0,ex2=0;
	for(int j=p;j<r;j++)
	{
		if(a[j]<=x)
		{
			i++;
			ex1=a[i];
			a[i]=a[j];
			a[j]=ex1;
		}
	}
	ex2=a[i+1];
	a[i+1]=a[r];
	a[r]=ex2;
	return i+1;

}
int randomizedpartition(int a[],int p,int r)
{
	int ex3=0,i=0;
	time_t t;
    srand((unsigned) time(&t));
	i=rand()%(r-p+1)+p;
	ex3=a[i];
	a[i]=a[r];
	a[r]=ex3;
	return partition(a,p,r);
}
void randomzedquicksort(int a[],int p,int r)
{
		int q=0;
	if(p<r)
	{
		q=randomizedpartition(a,p,r);
		randomzedquicksort(a,p,q-1);
		randomzedquicksort(a,q+1,r);
	}
}

(5)计数排序

计数排序假定输入树取自集合{0,1,2,...,k}。通过利用数组下标来确定元素的相对次序,该算法可在θ(k+n)时间内完成。

伪代码如下:

COUNTING-SORT(A,B,k)
for i←0 to k
do C[i]←0
for j←1 to length[A]
do C[A[j]]←C[A[j]]+1
//C[j]包含等于i的元素个数
for i←1 to k
do C[i]←C[i]+C[i-1]
//C[i]包含小于或等于i的元素个数
for j←length[A] downto 1
do B[C[A[j]]]←A[j]
     C[A[j]]←C[A[j]]-1


c语言代码如下:

int max(int a[],int k)
{
	int maax=0;
	for(int u=0;u<k;u++)
	{
		if(maax<a[u])
			maax=a[u];
	}
	return maax;
}
void couningsort(int a[],int k)
{
	
	int m=max(a,k);
	int *b=new int[k+1];
	int *c=new int[m+1];	
	for(int j=0;j<k;j++)
		b[j]=0;
	for(int i=0;i<=m;i++)
		c[i]=0;
	for( j=0;j<k;j++)	
		c[a[j]]++;
	for( i=1;i<=m;i++)
		c[i]=c[i]+c[i-1];
	for(j=0;j<k;j++)
	{	
		b[c[a[j]]-1]=a[j];
		c[a[j]]--;
	}
	for(j=0;j<k;j++)
		a[j]=b[j];
	delete[] b;
	delete[] c;
	
}