使用快速排序方法求第K大的数

快速排序

题目链接: https://www.nowcoder.com/practice/e016ad9b7f0b45048c58a9f27ba618bf?tpId=188&tqId=38052&rp=1&ru=%2Factivity%2Foj&qru=%2Fta%2Fjob-code-high-week%2Fquestion-ranking&tab=answerKey.
C语言


提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、基本思想

以降序为例。
基本思想:通过一趟快速排序,将待排序的序列分割成两段相互独立的序列,其中左边的序列都比右边序列大。再分别对这两部分序列进行排序,则可实现整体有序。
具体实现:选择一个中间数,把大于中间数的元素放在其左边,小于中间数的放在其右边。(这一步完成后,实际上就确定了中间数排序后应该在的位置),然后再分别还没有排序的左边序列和右边序列进行排序。
中间数的选择:可以第一个数,最后一个数,中间的数等等。

我们举个例子:
快速排序一趟
个人是这样理解的,每一次在找到比中间数大(小)的元素时,把找到的数放在蓝色的框里(想象它被扣掉了,需要填数字进去),放好后,这个被扣掉的地方,变成了刚刚所选的大(小)数的那个地方。然后,我们需要从另一边找比中间数小(大)数来填这个空。反复操作,直到左右两边都已经判断完毕,当前的这个空,即为中间数应在的位置。至此完成一趟快速排序。
以上操作的是一趟排序,结果是确定了中间数的位置。其左右两边的序列还需进行排序,而我们只需要以同样的方式分别对其左右两边进行快速排序即可,直到左右两边都只有一个元素时,整个序列即为有序序列。

一趟快速排序代码:

int FastSort(int* arr,int low,int high){
			//选择一个中间数,如果大于中间数,则放在左边,如果小于中间数则放在右边
			//中间数和high位置上的数进行比较,如果high位置上的数比中间数小,则high--,比较下一个。
			//直到比到比中间数大的时候 ,将这个大的数移到low的位置上,接下来low++,low位置上的数与中间数比较
			//如果low位置上的数比中间数大,则low++,比较下一个,直到比到比中间数小的时候,将这个小的数放到high的位置上,high--
			//重复以上步骤,直到low>=high,此时,中间数的正确位置为low,将中间数放在low位置上,完成一趟快速排序
			//接着分别对中间数两边的元素以同样的方式进行快速排序。直到最后只剩下一个元素,排序完成。 
			int t=arr[low];
			int i=low,j=high;
			while(i<j){
				while(i<j&&t>=arr[j]) j--;	
				arr[i]=arr[j];
				while(i<j&&t<=arr[i]) i++;
				arr[j]=arr[i];
			} 
			arr[i]=t;
			return i;
		}

完整的快速排序代码:

void Sort(int* arr,int l,int r){
			if(l>=r) return;
			int index=FastSort(arr,l,r);
			Sort(arr,l,index-1);
			Sort(arr,index+1,r);
		}
var foo = 'bar';

二、求第K大的数

知道了快速排序的原理后,我们怎么利用快速排序来求第K大的数?我们知道,一趟快速排序,确定了中间数在最终有序序列的所在位置,所以,如果我们对序列进行升序排序,那么排在第K个位置的是不是就是第K大的数呢?答案是的。
所以,我们只需要在快速排序时做一个简单的判断:判断当前这趟快速排序所确定的中间数的位置是不是k,

  1. 如果是,则说明当前这个中间数就是第K大的数;
  2. 如果当前这趟排序所确定的位置大于K,说明第K大的是在左边,只需对左边进行快速排序寻找;
  3. 如果当前这趟排序所确定的位置小于K,说明第K大的数在右边,需要对右边进行快速排序寻找。
    当找到第K大的数后,结束操作。剩余元素可能是无序的,如果我们只需要找到第K大的数,做到这里就可以了。

求第K大的数的代码

void FastSort(int* arr,int low,int high,int k){
		//int FastSort(int* arr,int low,int high){
			//选择一个中间数,如果大于中间数,则放在左边,如果小于中间数则放在右边
			//中间数和high位置上的数进行比较,如果high位置上的数比中间数小,则high--,比较下一个。
			//直到比到比中间数大的时候 ,将这个大的数移到low的位置上,接下来low++,low位置上的数与中间数比较
			//如果low位置上的数比中间数大,则low++,比较下一个,直到比到比中间数小的时候,将这个小的数放到high的位置上,high--
			//重复以上步骤,直到low>=high,此时,中间数的正确位置为low,将中间数放在low位置上,完成一趟快速排序
			//接着分别对中间数两边的元素以同样的方式进行快速排序。直到最后只剩下一个元素,排序完成。 
	int t=arr[low];
	int i=low,j=high;
	while(i<j){
		while(i<j&&t>=arr[j]) j--;	
		arr[i]=arr[j];
		while(i<j&&t<=arr[i]) i++;
		arr[j]=arr[i];
	} 
	arr[i]=t;
	//return i;
	if(i==k) return;
	if(i>k) FastSort(arr,low,i-1,k);
	else FastSort(arr,i+1,high,k);
}
//找出第k小的数
int findKth(int* a, int aLen,int n,int K) {
	FastSort(a,0,aLen-1,K-1);
	return a[K-1];
}

总结

一开始的时候,我是对序列进行降序来求第K大的数,发现第K个位置上不是第K大的,如果是降序排的话,第K大的数应该在aLen-K的位置上。编程路上,砥砺前行~


版权声明:本文为qq_42211773原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。