內部排序算法之快速排序

快速排序是一種性能較好的算法,有最好的平均性能。由冒泡排序算法改進,採用分治思想:

1.將整個區間劃分兩個子區間p1, p2和元素k, 使得p1區間的所有元素均小於k, p2區間的所有元素均大於或等於k(這裏k成爲樞軸元素),

2.再對p1和p2兩個區間分別重複步驟1, 如此遞歸

3.由於步驟1是就地排序,直到最後每個區間的元素個數爲1, 這樣整個區間就有序了。

實現步驟1的函數 

int Partion(int *p, int low, int high) 

這個函數根據選擇的樞軸元素不同, 實現也不同,常見的有:

1.第一個元素選爲樞軸元素

int Partion(int *p, int low, int high)
{
  while(high>low)
  {
    while(high>low && p[high]>p[low]) //#1
    {
      --high;
    }
    swap(p+high, p+low);

    for(high>low && p[high]>=p[low])  //注意這裏和#1處必須保證至少有一個地方取等號, 否則遇到相等的元素時會出現死循環, 函數不能退出。
    {
      ++low;
    }
    swap(p+high, p+low);
  }
  return low;
}
2.最後一個元素選爲樞軸元素
int Partion(int *p, int low, int high)
{
  int i, j = low;
  for(i=low; i<high-1; ++i)
  {
    if(p[i]<=p[high])
    {
       if(i!=j) // 避免不必要的交換
       {
         swap(p+i, p+j);
       }
       ++j;
    }
  }
  swap(p+j, p+high);
  return j;
}

當序列有序的時候, 不管是選第1個還是最後一個元素爲樞軸元素, 都會劃分一個長度爲1, 一個長度爲N-2的兩個子區間,子區間長度相差較大,所有子區間組成的樹不平衡,造成排序時間複雜度爲O(n^2),效率較低。可以採用隨機化的方法選擇樞軸元素:

int partion(int *p, int low, int high)
{
    int k = random() ;
    swap(p+k, p+low);  // 或者swap(p+k, p+high); 
   // 隨機選擇一個元素與第一個元素或者最後一個元素交換, 作爲樞軸元素

   // 
   // 接下來與第一個或者最後一個元素作爲樞軸元素相同 
....
}

 這樣效率可以達到O(n*logn)。

通常快速排序具有最好的平均性能,時間複雜度爲O(n*logn), 常數因子較其他同類算法(時間複雜度爲O(n*logn)的算法)小。可是當區間元素有序(正序或者逆序)的時候,快速排序就蛻變成時間複雜度爲O(n^2)的算法了。

代碼實現

1.遞歸實現

void static qsort(int *p, int low, int high)
{
	if(low < high)
	{
		int pivot = partion(p, low, high);
		qsort(p, low, pivot-1);
		qsort(p, pivot+1, high);
	}
}

2. 非遞歸實現

void qsort(int *p, int low, int high)
	if(low < high)
	{
		Stack stack;
		init_stack(&stack);
		int mid = partion(p, low, high);
		if(mid-1 >= 0)
		{
			push_stack(&stack, low);
			push_stack(&stack, mid-1);
		}
		if(mid+1 <= high)
		{
			push_stack(&stack, mid+1);
			push_stack(&stack, high);
		}
		while(!empty_statck(&stack))
		{
			int m, n;
			if(pop_stack(&stack, &n) && pop_stack(&stack, &m))
			{
				mid = partion(p, m, n);
				if(mid-1 >= m)
				{
					push_stack(&stack, m);
					push_stack(&stack, mid-1);
				}
				if(mid+1 <= n)
				{
					push_stack(&stack, mid+1);
					push_stack(&stack, n);
				}
			}
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章