C语言中快速排序和插入排序优化的实现

2020-01-06 14:02:54于海丽

55 41 26 59 53 58 97 93 i = 4,A[i]位置为53,A[i] < key,swap(++p, i),p = 3:
55 41 26 53 59 58 97 93 i = 5,A[i]位置为58,A[i] > key,不做任何改变。 
i = 6,A[i]位置为97,A[i] > key,不做任何改变. 
i = 7,A[i]位置为93,A[i] > key,不做任何改变.结束循环。此时p为key的最终位置。还需一步把key值填入p位置。
最后swap(l, p)即把Key值放到最终位置上了。至于为什么要交换l,p的位置,可以另拿一组数据试一下:55,41,59,26,99,58,97,93。

完整的程序1

/*l, u 代表待排序部分的下界和上界*/


void qsort(int l, int u)
{
 /*递归结束条件是待排序部分的元素个数小于2*/
 if(l >= u)
 {
  return;
 }
 
 int p = l;
 for(int i = l+1; i <= u; i++)
 {
  if(A[i] < A[l])
  {
   swap(++p, i);
  }
 }
 swap(l, p);
 
 qsort(l, p-1);
 qsort(p+1, u);
}

这就是第一代快速排序算法,正常情况下其复杂度为nlogn,但在考虑一种极端情况:n个相同元素组成的数组。在n-1次划分中每次划分都需要O(n)的时间,所以总的时间为O(n^2)。使用双向划分就可以避免这个问题。

双向划分快速排序


/*l, u 代表待排序部分的下界和上界*/
void qsort(int l, int u)
{
 /*递归结束条件是待排序部分的元素个数小于2*/
 if(l >= u)
 {
  return;
 }
 
 key = A[l]
 for(int i = l, j = u+1; i <= j;)
 {
  do i++ while(i <= u && A[i] < key));
  do j-- while(A[j] > key);
  if(i > j)
  {
   break;
  }
  swap(i, j);
 }
 swap(l, j);
 
 qsort(l, j-1);
 qsort(j+1, u);
}

插入排序优化
插入排序的精髓就是首先将第一个元素视为有序子数组x[0...0],然后插入x[1]...x[n-1].思想很简单,代码也很简单,简单的代码有没有优化的空间呢?编程珠玑中提供了几个优化后的方案,效率提高了70%之多。

简单的实现(sort1)


void insertSort(int *array, size_t size)
{
 for(size_t i = 1; i < size; i++)
 {
  for(int j = i; j > 0 && array[j - 1] > array[j]; j--)
  {
   swap(array[j - 1], array[j]);
  }
 }
}

优化思路
    内循环的swap函数可能不如内联函数快些,所以第一步优化将该swap函数展开,据作者说,展开后效率提高了60%。

优化代码(sort2)


void insertSort(int *array, size_t size)
{
 for(size_t i = 1; i < size; i++)
 {
  for(int j = i; j > 0 && array[j - 1] > array[j]; j--)
  {
   int t = array[j];
   array[j] = array[j - 1];
   array[j - 1] = t;
  }
 }
}