排序算法总结

1 冒泡排序

      --比较相邻两个数据,若前面的数据大于后面的数据,则对其进行交换

      --这样对整个数组从头到尾操作一遍,最大的数据便沉到了数组末尾

      --接下来将数组长度减一,再进行比较,这样第二大数据沉到了数组倒数第二个位置上,依次类推,便可达到排序

 可看出,冒泡排序复杂度为O(n^2),由于两相邻数据相等时不必进行交换,所以冒泡排序是稳定的!

改进方案: 可以设一个标志位,若这一趟发生了数据交换,则置标志位位true,若没有发生,则值false,很明显,若有一趟没有发生数据交换,即标志位为false,则说明数组已排好序,即可终止排序!

 

2  插入排序  :将待排序的数字插入已排序的数组

     --初始时,数组第一个数据自成一个有序区,无序区位a[1--n].令i=1

     --将a[i]插入到有序数组a[0---i-1]中形成a[0--i]的有序区

     --++i并重复第2步,直到数组末尾,排序完成

void insert_sort(int nums[],int len)
{
	if(nums==NULL || len<=0)  return;
        //i指向已排序数组的末尾  j指向待排序的数据
	int i=0,j=1;
	while(j<len)
	{
		int key=nums[j];
		int k=i;
                //寻找合适的位置将数据插入到排序数组中
		while(k>=0 && nums[k]>key)
			{
				nums[k+1]=nums[k];
				--k;
			}
		if(k==-1)
			nums[0]=key;
		else
			nums[k+1]=key;
		++j;
		++i;
	}
}

将数据插入到已排序数组需O(n),所以插入排序的复杂度为O(n^2)! 插入排序对相等元素的插入规则也是一样,不回改变其顺序,因此

插入排序也是稳定的排序!

  3   选择排序

       -- 在整个数组中找到最小的元素 与第一个元素位置交换

       --从第二个元素起,在其后找最小的元素,并与第二个元素交换

       --依次类推,可完成排序

void select_sort(int nums[],int len)
{
	if(nums==NULL || len<=0)  return;
        //min指向最下元素值,key指向最小元素下标
	int min,key;
	for(int i=0;i<len;++i)
	{
		key=i;
		min=nums[i];
                //在(i-n)的范围内寻找最小元素,与i作交换
		for(int j=i+1;j<len;++j)
		{
			if(nums[j]<min)
			{
				min=nums[j];
				key=j;
			}
		}
		if(i!=key)
		{
			int t=nums[i];
			nums[i]=nums[key];
			nums[key]=t;
		}
	}
}

 可看出 选择排序复杂度为O(n^2)  也是稳定排序!

4 归并排序

   --将数组拆分成两个字数组,问题便成了对两个字数组排序,再将两个已排序的字数组合并即可

   --对两个子数组排序,是一个递归的过程,当递归到只有一个数据时,即可认为排好序!

   --所以问题关键在合并两个有序子数组的问题上!

​

​
//合并两个有序子数组
void merge_sumArray(int nums[],int first,int mid,int last)
{
	int len=last-first+1;
        //用copy保存合并的数据
	int *copy = new int[len];
	int i=first,j=mid+1,k=0;
	while(i<=mid && j<=last)
	{
                //取两个子数组中数据的较小者
		if(nums[i]<nums[j])
			copy[k++]=nums[i++];
		else 
			copy[k++]=nums[j++];
	}
        //处理子数组中未处理完的数据
	while(i<=mid)
		copy[k++]=nums[i++];
	while(j<=last)
		copy[k++]=nums[j++];
        //将copy中的数据复制到原数组对应位置
	for(int p=0;p<len;++p)
		nums[first++]=copy[p];
	delete []copy;
}

void merge_sort(int nums[],int first,int last)
{
        //last对应数组尾端数据,first对应数组首端数据
	if(first<last)
	{
		int mid=(first+last)/2;
                //对两个子数组排序
		merge_sort(nums,first,mid);
		merge_sort(nums,mid+1,last);
                //合并两个有序子数组
		merge_sumArray(nums,first,mid,last);
	}

}

void merge_sort(int nums[],int len)
{
	if(nums==NULL || len<=0)  return;
	merge_sort(nums,0,len-1);
}

  合并两个有序子数组耗时o(n),由于递归是折半的,所以需递归O(lgn)次, 所以归并排序总的复杂度位O(nlgn)!   是稳定排序

 

5 快速排序

      --首先对整个数组。取一个基准值,将数组分为两半,小于基准值的在左边,大于基准值的在右边

      --取得基准值的下标,对其两边的数据分别进行第一步的操作

      --递归第二步的操作,即可完成排序!

//挖坑填数操作,将数组以一个基准数位基准分为两半
int partition(int nums[],int first,int last)
{
        //取数组首端数据作为基准数
	int key=nums[first];
    
	int i=first,j=last;
	while(i<j)
	{
                //从数组尾端寻找第一个小于基准数的数据
		while(nums[j]>key && i<j)
			--j;
		if(i<j)   //用该数据填充之前的坑 并留出一个新坑
			nums[i++]=nums[j];
                //从数组首端寻找第一个大于基准数的数据
		while(nums[i]<key && i<j)
			++i;
		if(i<j)   //用该数据填充之前的坑,并留出一个新坑
			nums[j--]=nums[i];
	}
	nums[i]=key;
	return i;
}
void quick_sort(int nums[],int first,int last)
{
        //数组只剩下一个元素时,停止递归
	if(first==last)
		return;
        //对整个数组作partition操作,分为两半
	int index=partition(nums,first,last);
        //对左边数据递归
	if(index>first)
		quick_sort(nums,first,index-1);
        //对右边数据递归
	if(index<last)
		quick_sort(nums,index+1,last);
}
void quick_sort(int nums[],int len)
{
	if(nums==NULL || len<=0)  return;
	quick_sort(nums,0,len-1);
}

整个挖坑填数耗时O(N),递归lgn次,总的复杂度为O(lgn)  在寻找大于或小于基准数的数据的时候,我们有可能将两个相邻且相等数据其中一个移动到另一边,这样便破坏的稳定性,因此快速排序是不稳定的!    

  快速排序的改进方案:随机选择基准数,区间内数据较少时可选用其他的排序方法,以减少递归深度!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值