交换排序

交换排序的核心思想是:

            给定一组数据,两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。

         基于交换思想的排序方法有两种,冒泡排序和快速排序。

冒泡排序

             基于交换的思想其实比较符合人们的认知,冒泡排序就是依次比较两个关键字,如果发现两者的关系是逆序,就交换,第一次两两比较可以得出最大或最小的在相应位置,第二次比较可以得出在剩下的数中最大的或最小的,也就是整个数据中次大的或次小的。一个数要比较n-1次,共比较n(n-1)次,最坏交换次数是n-1 + n-2 + n-3 + …… + 1 = n(n-1)/2次,所以时间复杂度是o(n^2),原地排序,空间复杂度o(1)。

void bubbleSort(int* a, int len) 
{ 
    int i,j,key; 
    for (i=0; i<len-1; i++)//一共比较n-1次
     {
          for (j=0; j<len-i-1; j++)//第i次只用比较到前面的len-i位置的数
          {
               if (a[j] > a[j+1])//比较交换
               {
                    key = a[j+1];
                    a[j+1] = a[j];
                    a[j] = key;
               }
          }
     }
}

快速排序

            冒泡排序有很多重复的比较,它的比较过程没有记录下可供下一次比较的有用信息。针对这一问题,有很多改进的排序算法,这里只介绍基于比较的快速排序。

 时间复杂度和空间复杂度分析

           快速排序是每次找到一个划分值排好位置,如升序排序,在它左边的数都比它小,在它右边的数都比它大,然后使用分治的思想递归左右两部分,使得每一部分都排好序。因为它划分出来的左右部分不用再比较,所以减少了比较次数。如果每一次划分左右两边个数都相等的话,划分log2n次,每次划分时间是n,时间复杂度是o(nlog2n),最坏情况是每次划分之后都有一边是1个元素,这样快速排序就变成了冒泡排序,时间复杂度o(n^2).

          快速排序的空间复杂度分析:由于借助递归栈,最坏栈深度是n,最好是(log2n)+ 1(包括最外层的参数进栈).

          经实践检验,快速排序是同类排序算法中时间复杂度常数因子最小的排序算法,就是说它的平均性能最好,所以叫快速排序。

 算法的改进

       1.为进一步提高快速排序的效率,使其不至于变成冒泡排序,取哨兵可以采用a[left], a[(right+left)/2] 和 a[right]三者取中的办法。还可以采用更为保险的办法,取中位数的办法,取中位数可以做到o(n)级别的复杂度。

       2.在数据量比较小的情况下,快排不如插入排序。所以可以用插入排序代替小数据量的快排。

       3.在有大量重复元素的情况下,可以把重复元素记录下来不做比较。在划分的过程中,在指针low+1和high-1的同时,交换相邻的两个记录,同时设置两个布尔型变量标记指针low和high在移动过程中是否有进行过交换记录的操作,如果没有,则不再需要对低端或高端子表进行排序。具体的代码参考博客快速排序的优化

int partition(int a[], int left, int right)
{
//一次划分,把最左边的数排好位置
	int low = left;
	int high = right;
	int key = a[low]; //第一个记录作为哨兵
	while (low < high)
	{
		while (low<high && key<=a[high]) high--;
		a[low] = a[high]; //比哨兵小的放在左边
		while (low<high && key>=a[low]) low++;
		a[high] = a[low]; //比哨兵大的放在右边
	}
	a[low] = key;  //哨兵放在合适的位置,左边都是比它小的,右边都是比它大的。
	return low; //返回哨兵所在位置
}

void quick_sort(int a[], int left, int right)
{
	int s;
	if (left >= right)
		return;
	s = partition(a, left, right);
	quick_sort(a, left, s-1);
	quick_sort(a, s+1, right);
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值