几种排序算法

几种排序算法

插入排序

向已经排好序的序列依次插入元素
时间复杂度:

  1. 循环的嵌套,为 o(N^2)
  2. 如果序列已经被排好序,则为 o(N) (因为内部的’for’不起作用)
  3. 含有x个逆序对数,则需要做x次交换操作
  4. 含有N个元素的数组,最多有 N(N-1)/2个逆序对数,平均 N(N-1)/4个
  5. 算法的平均时间复杂度为 Ω(N^2)
    代码如下:
void insert_sort(int a[],int num)//a为要排序的数组,num为数组元素个数,下同	
{
	int j,p,tmp;
	for(p=1;p<num;p++)
	{
		tmp=a[p];
		for(j=p;j>=1&&a[j-1]>tmp;j--)
		{
			a[j]=a[j-1];
		}
		a[j]=tmp;
	}
}

shell排序

将区间拆分,间隔为increment,每隔increment,用insert排序
之前已经降低了逆序数,因此再用insert排序会快很多
希尔排序的时间复杂度取决于increment的选取
increment很差的情况下,有可能在increment>1是,均不进行排序,全部放到increment=0是完成
希尔increment的取法:h(t)=[N/2] h(t+1)=[h(t)/2]
时间复杂度的上界为 Θ(N^2)
Hibbard increment的取法: 1,3,7,…,2^k-1 (更好)
时间复杂度上界为 Θ(N^3/2)
代码如下:

void shell_sort(int a[],int num)
{
	int i,j,increment,tmp;
	for(increment=num/2;increment>0;increment/=2)
	{
		for(i=increment;i<num;i++)
		{
			tmp=a[i];
			for(j=i;j-increment>=0&&a[j-increment]>tmp;j-=increment)
			a[j]=a[j-increment];
			a[j]=tmp;
		}
	}
}

堆排序

先建大根堆,后依次将堆顶与堆尾交换,完成新堆顶的下沉(以已排好的元素前一个元素为堆尾)
时间复杂度:
建堆 o(N)
堆的删除 每次o(log(N)) 总共o(Nlog(N))
总共 o(Nlog(N))

#define leftchild(i) (2*i+1)
void swap(int *a,int *b) //交换函数
{
	int tmp;
	tmp=*a;
	*a=*b;
	*b=tmp; 
} 
void percdown(int a[],int i,int num) //堆下沉排序,从第i号元素向下维护堆为大根堆
{
	int child;
	int tmp;
	for(tmp=a[i];leftchild(i)<num;i=child)
	{
		child=leftchild(i);
		if(child+1<num&&a[child]<a[child+1])//找两孩子中较大的孩子 
		child++;
		if(tmp<a[child])//本质:插入排序 
		a[i]=a[child];
		else break;
	}
	a[i]=tmp;
}
void heap_sort(int a[],int num)
{
	int i;
	for(i=num/2-1;i>=0;i--)//完成建堆  num/2-1:最后一个非终端结点 
	percdown(a,i,num);
	for(i=num-1;i>0;i--)
	{
		swap(&a[0],&a[i]);/*删除最大元方法:将最大元(堆顶)与堆尾交换,其余部分堆下沉*/ 
		percdown(a,0,i); 
	 }
}

归并排序

void merge(int a[],int tmparr[],int lp,int rp,int re)
{
	int le=rp-1;
	int tp=lp;
	int i,totalnum=re-lp+1;
	while(lp<=le&&rp<=re)
	{
		if(a[lp]<=a[rp])
		tmparr[tp++]=a[lp++];
		else
		tmparr[tp++]=a[rp++];
	}
	while(lp<=le)
	tmparr[tp++]=a[lp++];
	while(rp<=re)
	tmparr[tp++]=a[rp++];
	for(i=0;i<totalnum;i++,re--)
	a[re]=tmparr[re];
}
void msort(int a[],int tmparr[],int left,int right)
{
	int center;
	if(left<right)
	{
		center=(left+right)/2;	//分治 
		msort(a,tmparr,left,center);
		msort(a,tmparr,center+1,right);
		merge(a,tmparr,left,center+1,right);//合并 
	}
}
void merge_sort(int a[],int num)
{
	int *tmparr;
	tmparr=(int*)malloc(num*sizeof(int));
	//共用一个tmparr,而不是分别在merge里建立tmparr,这样节省空间
	//空间复杂度  o(N) 和o(Nlog(N)) 的区别
	//问题:占用额外的线性内存(tmp),且copy耗时
	//是大部分外排的基石 
	if(tmparr!=NULL)
	{
		msort(a,tmparr,0,num-1);
		free(tmparr);
	}
	else 
		printf("No space for tmparr\n");
	return;
}

快速排序

int median3(int a[],int left,int right)
{
	int center=(left+right)/2;
	//找中三数中中间的树
	if(a[left]>a[center])
	swap(&a[left],&a[center]);
	if(a[left]>a[right])
	swap(&a[left],&a[right]);
	if(a[center]>a[right])
	swap(&a[center],&a[right]);
	//A[Right]肯定比枢轴A[Center]大,位于枢轴右侧,因此不需要参与后续的放枢轴左右的比较过程中
	swap(&a[center],&a[right-1]);
	return a[right-1];
}
void Qsort(int a[],int left,int right)
{
	int i,j;
	int pivot;
	if(right-left>=3)
	{
		pivot=median3(a,left,right);
		i=left;
		j=right-1;
		while(1)
		{
			while(a[++i]<pivot);
			while(a[--j]>pivot);
			if(i<j)
			swap(&a[i],&a[j]);
			else
			break;
		}
		swap(&a[i],&a[right-1]);
		Qsort(a,left,i-1);
		Qsort(a,i+1,right); 
	}
	else
	insert_sort(a+left,right-left+1);
 } 
void quick_sort(int a[],int num)
{
	Qsort(a,0,num-1);//接口统一	
} 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值