1. 程式人生 > >線性時間複雜度求陣列中第K大的數

線性時間複雜度求陣列中第K大的數

演算法思想基於快速排序,詳細步驟如下:

1. 隨機選擇一個分割點

2. 將比分割點大的數,放到陣列左邊;將比分割點小的數放到陣列右邊;將分割點放到中間(屬於左部分)

3. 設左部分的長度為L,

              當K < L時,遞迴地在左部分找第K大的數

              當K > L時,遞迴地在右部分中找第(K - L)大的數

              當K = L時,返回左右兩部分的分割點(即原來的支點),就是要求的第K大的數

     以上思想的JAVA程式碼實現如下:

package Sort;

public class TheKth {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a[] = {1,2,3,4,5,6,7,8,9,10};  
	    int r = selectk(a, 0, a.length- 1, 6);  
	    System.out.println(r);
	}
	//基於快速排序思想,求陣列a中第k大的數,low和high分別為陣列的起始和結束位置
	//時間複雜度為o(n),n為陣列的長度
	//1<=k<=n
	//如果存在,返回第k大數的下標,否則返回-1
	public static void swap(int a,int b)
	{
		int tmp;
		tmp=a;
		a=b;
		b=tmp;
	}
	public static int selectk(int a[], int low, int high, int k)
	{
		if(k <= 0)
			return -1;
		if(k > high - low + 1)
			return -1;
		int pivot = low + (int)Math.random()%(high - low + 1);    //隨即選擇一個支點
		swap(a[low], a[pivot]);
		int m = low;
		int count = 1;

		//一趟遍歷,把較大的數放到陣列的左邊

		for(int i = low + 1; i <= high; ++i)
		{
			if(a[i] > a[low]) 
			{
				swap(a[++m], a[i]);
				count++;              //比支點大的數的個數為count-1
			}
		}
		swap(a[m], a[low]);           //將支點放在左、右兩部分的分界處
		if(count > k)
		{
			return selectk(a, low, m - 1, k);
		}
		else if( count < k)
		{
			return selectk(a, m + 1, high, k - count);
		}
		else
		{
			return m;
		}
	}

}