1. 程式人生 > >快速排序遞迴思想 n個元素中第m小的元素

快速排序遞迴思想 n個元素中第m小的元素

利用快速排序的思想,編寫一個遞迴演算法,求出給定的n個元素中第m個最小的元素

思路:取陣列第m個元素也就是a[m-1]作為每一次迴圈的一個閾值,將大於a[m-1]的全部放在陣列的右邊,小於a[m-1]的全部放在陣列的左邊,如果一直這樣迴圈下去,那麼最後a[m-1]這個單元中存放的就一定是第m小的資料。
 
程式碼分析:至於程式中比較難理解的我覺得是:
  if(j < m-1) left = i;  //這一句的意思是,程式是想尋找第m小的資料,但是j<m-1,表示現在這個閾值比第m個最小的數還小,然而存放在陣列中,比當前閾值大的數的集合中的第一個數的下標正好是i,因為i是從while(privot < a[i]) i++;

這個語句中跳出來的,所以這個時候將左查詢範圍設定為i。
  if(i > m-1) right = j; 跟上面的理解差不多。
  
注意:其實這兩個if判斷來修正left和right查詢範圍的語句完全可以不需要,因為不修改的話每次都是從最左端查詢到最右端,結果是一定能夠查找出來的,只是效率方面可能就沒有加上這兩句好了。

PS:本文借鑑了https://blog.csdn.net/laoniu_c/article/details/38127967的思路,根據題意進行程式設計,程式碼如下:

#include <iostream>
using namespace std;

int findm_min(int *a, int n, int m, int left, int right)
{
	int piv = a[m-1];	//取闕值 
	int i = left, j = right; 
	if(i < j)
	{
		//將右端比闕值小的數和左端比闕值大的數交換位置 
		while(piv < a[j]) j--;
		while(piv > a[i]) i++;
		if(i < j)
		{
			//通過位運算交換兩個數的位置
			a[i] = a[i] ^ a[j];
			a[j] = a[i] ^ a[j];
			a[i] = a[i] ^ a[j];
			i++, j--;
		}
		if(i == j && a[i] == piv)
			return piv;	//符合預想條件,返回最後結果
	}
	else return a[m-1];
	//優化演算法
	if(j < m - 1) left = i;
	if(i > m - 1) right = j;
	//遞迴
	findm_min(a, n, m, left, right);
}

int main()
{
	int n, m;
	//輸入n,m
	cout << "請輸入n和m:" << endl;
	cin >> n >> m;
	//輸入陣列元素
	int *a = new int[n];
	cout << "請輸入n個數:" << endl;
	for(int i = 0; i < n; i++) cin >> a[i];
	//計算並輸出最後結果
	cout << n << "個數中第" << m << "小的數為:" << endl;
	cout << findm_min(a, n, m, 0, n - 1) << endl;
	
	return 0;
}