寻找最大的K个数(下)

接着昨天的写,里面的代码包含昨天的


  1 #include <iostream>
2 using namespace std;
3 #define N 50
4
5 //初始化数组
6 int a[] = {6, 2, 3, 4, 4, 3, 1, 2, 4, 4};
7 //int a[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
8 //int a[] = {1, 2, 3, 4, 5, 6};
9 //int a[] = {6, 2, 3, 9, 4, 10, 1, 20, 40, 5};
10 int n = 10;
11 int K = 4;
12
13 //快速排序,o(nlogn),最应该想到的思路,排好序要多大数就输出多大数
14 /*
15 partition就是挖第一个洞,从后往前找,找到,挖起来,把前面的洞埋上,再从前往后找,找到,挖起来,把后面的洞埋上,直到最后,high=low了,把这个洞补上
16 */
17 int partition(int* p, int low, int high)
18 {
19 int i;
20 int pivot;
21 //把第一个数拿出来,挖个洞
22 pivot = p[low];
23 while (low < high)
24 {
25 //从后往前找,找到比pivot小的值
26 while (low < high && p[high] <= pivot)
27 high--;
28 //然后后面的数埋上前面的洞
29 //Note这里无须再加个if,因为即使相同了,那我再做一步也无妨,而且也无须把low指针往上移,因为,到时候我可以再判断一次,还是可以移动的
30 p[low] = p[high];
31
32 //从前往后找,找到比pivot大的值,然后把前面的数埋上
33 while (low < high && p[low] >= pivot)
34 low++;
35 p[high] = p[low];
36 }
37 //这里low和high已经相同了,所以也可以写成p[high]=pivot,这一步就是把洞埋上
38 p[low] = pivot;
39 return low;
40 }
41 /*
42 其实,两个可以写一起,但是,分开写更清楚
43 quickSort函数就是当low<high时,进行一次partition,然后再对分开的两块进行quickSort
44 */
45 void quickSort(int* p, int low, int high)
46 {
47 if(low < high)
48 {
49 int breakpoint = partition(p, low, high);
50 quickSort(p, low, breakpoint - 1);
51 quickSort(p, breakpoint + 1, high);
52 }
53 }
54
55 //堆排序, o(nlogk),考虑到只需取K大的数,那就无须对n个数都排序,只需记录下k个即可
56 int heap[N];
57 /*
58 //这里有点疑问哦,考虑到heap数组可能比较大,所以想定义成全局变量,可是这样就不必传递参数勒,定义成局部变量,参数又太多
59 目前定义成全局变量
60 input: lastIndex指heap数组要插入的value的位置(是要插入的位置哦); value指要插入的数字
61 function: heap数组是从index=0开始储存的,就是把value储存heap数组内,并进行相应的调整,符合最大堆的性质
62 */
63 void MaxHeapPush(int lastIndex, int value)
64 {
65 //把value放在堆的末尾
66 heap[lastIndex] = value;
67 //记录下末尾的index
68 int index = lastIndex;
69 // 不断向上调整
70 while (index)
71 {
72 //若比上面的大,就交换
73 if (heap[index] > heap[(index - 1) / 2])
74 {
75 int temp = heap[index];
76 heap[index] = heap[(index - 1) / 2];
77 heap[(index - 1) / 2] = temp;
78 }
79 //否则,说明已经调整好了,立即停止
80 else
81 break;
82 //若没有break出来,就要一直调整了,所以index要变动
83 index = (index - 1) / 2;
84 }
85 }
86 /*
87 input:
88 p数组要初始化数组,提供数据的
89 n表示该数组的长度,c就是麻烦,连长度都要传入
90 heapSize表示要维护的堆的大小,Note,一定要大于K哦
91 */
92 void MaxHeapInit(int *p, int n, int heapSize)
93 {
94 int i, lastIndex;
95 lastIndex = 0;
96 for (i = 0; i < n; i++)
97 {
98 //依次插入
99 MaxHeapPush(lastIndex, p[i]);
100 // 若比预定好的堆的大小小的话,最后一个value的值就要增加了
101 if (lastIndex < heapSize)
102 lastIndex++;
103 }
104 }
105 /*
106 input: lastIndex是要删除的value的位置(这里千万要注意,其实,跟前面的lastIndex有点不一样)
107 */
108 int MaxHeapPop(int lastIndex)
109 {
110 // 交换头尾value
111 int temp, i;
112 temp = heap[0];
113 heap[0] = heap[lastIndex];
114 heap[lastIndex] = temp;
115 // 向下调整
116 i = 0;
117 int child = 2 * i + 1;
118 while (child < lastIndex)
119 {
120 //若有右孩子节点,且右节点比左节点大,那要只需要比较右节点即可
121 if (child + 1 < lastIndex && heap[2 * i + 2] > heap[2 * i + 1])
122 {
123 child = child + 1;
124 }
125 //若孩子节点比父节点大,两个节点交换
126 if (heap[child] > heap[i])
127 {
128 temp = heap[child];
129 heap[child] = heap[i];
130 heap[i] = temp;
131 }
132 //否则说明已经有序,停止
133 else
134 break;
135 // 变化孩子节点的index
136 child = 2 * i + 1;
137 }
138 // 返回末尾value
139 return heap[lastIndex];
140 }
141
142 //快排的优化,时间复杂度还是o(nlogn),但是时间会大大减少
143 /*
144 由于只需要知道前K大数,没必要把所有的数都进行排序,而快排的思想就是找到一个值一分为二,所以,我们正好利用这一点
145 有了之前写好的partition函数,实现起来就就是方便!!
146 */
147 void optQuickSort(int* p, int low, int high, int k)
148 {
149 int cur = partition(p, low, high);
150 if (cur - low > k)
151 optQuickSort(p, low, cur - 1, k);
152 else if (cur - low < k - 1)
153 optQuickSort(p, cur + 1, high, k - (cur - low + 1));
154 }
155
156 //部分排序,o(nK)
157 /*
158 这本应该最新想到的呀,若K=1,其实就只需找最大值就好了
159 当K<logn时,才有用武之地呀
160 */
161 void partSort(int* p, int n, int k)
162 {
163 int i, j, maxI, temp;
164 for (i = 0; i < k; i++)
165 {
166 maxI = i;
167 for (j = i; j < n; j++)
168 {
169 if (p[j] > p[maxI])
170 maxI = j;
171 }
172 if (i != maxI)
173 {
174 temp = p[maxI];
175 p[maxI] = p[i];
176 p[i] = temp;
177 }
178 }
179 }
180
181 //时间换空间的办法,o(n)
182 /*
183 适用于整数,且范围不是很大的情况
184 如果没有重复的话,还可以用bit数组
185 */
186 void findCount(int*p, int n, int k)
187 {
188 int count[N] = {0};
189 int i, j, sumCount;
190 //首先先对输入的元素进行计数
191 for (i = 0; i < n; i++)
192 {
193 count[p[i]] += 1;
194 }
195 sumCount = 0;
196 for (i = N - 1; i > 0; i--)
197 {
198 sumCount += count[i];
199 //若累计最大的数大于k了,就把多余的部分去掉,把最大的k个数输出
200 if (sumCount > k)
201 {
202 for (j = 0; j < count[i] - (sumCount - k); j++)
203 cout<<i<<" ";
204 break;
205 }
206 //若累计的没有到达K,那就直接输出啦
207 else
208 {
209 for (j = 0; j < count[i]; j++)
210 cout<<i<<" ";
211 }
212 }
213 }
214
215 int main()
216 {
217 int i, j;
218 for (i = 0; i < n; i++)
219 cout<<a[i]<<" ";
220 cout<<endl;
221 /*
222 //快排,若取前K大的数,只需从末尾到前输出K个数即可
223 quickSort(a, 0, n - 1);
224 for (i = 0; i < n; i++)
225 cout<<a[i]<<" ";
226 cout<<endl;
227
228 //注意这里之所以乘以2,是因为只维护K个数字的堆,不能得到前K个大的数!!
229 MaxHeapInit(a, n, K * 2 - 1);
230 for (i = 0; i < n; i++)
231 cout<<heap[i]<<" ";
232 cout<<endl;
233 // 输出,这里的lastIndex是变化的哦,因为之前维护的2 * K - 1的堆,所以这里也应该是2 * K - 1
234 for (i = 0; i < K; i++)
235 cout<<MaxHeapPop(2 * K - 1 - i)<<" ";
236 cout<<endl;
237
238 optQuickSort(a, 0, n - 1, K);
239
240 partSort(a, n, K);
241 for (i = 0; i < n; i++)
242 cout<<a[i]<<" ";
243 cout<<endl;
244 */
245 findCount(a, n, K);
246 system("pause");
247 return 0;
248 }

寻找最大的K个数(下),布布扣,bubuko.com

时间: 2024-08-06 20:07:01

寻找最大的K个数(下)的相关文章

寻找最小的K个数

寻找最小的K个数 题目描述:查找最小的K个数 题目:输入n个整数,输出其中最小的K个数 例如,输入1.2.3.4.5.6.7.8这8个数字,则最小的4个数字为1.2.3.4. 第一节.各种思路,各种选择 要求一个序列中最小的K个数,按照惯有的思维方式,很简单,先对这个序列从小到大排序,然后输出前面的最小的K个数即可: 至于选取什么样的排序方法,第一时间应该想到的是快速排序,我们知道,快速排序平均时间复杂度为O(nlogn),然后再遍历序列中前K个元素输出,即可,总的时间复杂度为O(nlogn +

寻找最大的K个数

编程之美有一道考察多种排序的题目,题目如下: 有一个长度为N的无序数组,假定其中的每一个元素都各不相等,求其中最大的K个数. 作者对于此题目结合各种排序算法给出了五种解法思路. 解法一: 使用快速排序或堆排序对它们元素进行排序,整个排序的时间复杂度为O(N*log2N),然后取出前K个,时间复杂度为O(K),总时间复杂度O(N*log2N)+O(K)=O(N*log2N).根据题目要求,并不需要后N-KN-K个数有序,而只需要寻找最大K的个数,因此可以用选择排序和交换排序进行部分排序来筛选最大的

编程之美2.5 寻找最大的K个数

在一个数组中寻找最大的K个数,我们首先说一种非常简单的方法,利用快速排序中的分割算法,即我们经常看见的partition.这个函数会返回一个 int 类型的值,这个值代表的是前一半数字和后一半数字的分割点,前一半数字都小于等于后一半数字(递增排序),所以,我们只要找到相对应的分割点,即可以找到最大的K个数,或者最小的K个数,这就是利用线性方法可以完成任务的方法. 首先,给出函数声明: int DutPartition(int*, int, int); void DutFindMaxKInArra

寻找最小的k个数(update)

类似编程之美中寻找最大的k个数 解法一: 题目没有要求最小的k个数有序,也没要求最后n-k个数有序.既然如此,就没有必要对所有元素进行排序.这时,咱们想到了用选择或交换排序,即: 1.遍历n个数,把最先遍历到的k个数存入到大小为k的数组中,假设它们即是最小的k个数: 2.对这k个数,利用选择或交换排序找到这k个元素中的最大值kmax(找最大值需要遍历这k个数,时间复杂度为 O(k) ): 3.继续遍历剩余n-k个数.假设每一次遍历到的新的元素的值为x,把x与kmax比较:如果 x < kmax

编程之美之2.5 寻找最大的K个数

[题目] 有很多无序的数,从中找出最大的K个数.假定他们都不相等. [解法一] 如果数据不是很多,例如在几千个左右,我们可以排一下序,从中找出最大的K个数.排序可以选择快速排序或者堆排序 [cpp] view plaincopy #include<stdio.h> #include<stdlib.h> int cmp(const void *a,const void *b){ return *(int *)a - *(int *)b; } int main(){ int n,k;

编程之美之寻找最大的k个数

这个题目很常见,方法也很多,这里总结了编程之美给出的几个比较好的方法,也算是对这个问题的一个总结. 方法一.partition算法,每次partition的复杂度为O(n),总的平均时间复杂度为O(nlogn) 分析:运用partition算法,如果返回的provit > k-1,则说明要找的数都在前面,把end= provit-1;如果provit < k-1,表明找到一部分,先把部分数据保存,然后start = provit + 1;如果正好相等,则保存后结束,具体代码如下: int pa

【编程之美】2.5 寻找最大的k个数

有若干个互不相等的无序的数,怎么选出其中最大的k个数. 我自己的方案:因为学过找第k大数的O(N)算法,所以第一反应就是找第K大的数.然后把所有大于等于第k大的数取出来. 写这个知道算法的代码都花了2个多小时,反思,太慢了. 注意边界条件,不要混混沌沌的. /************我自己的解法*****************/ //选择数组a[N]中最大的第k个数 int Select(int * a, int N, int k) { if(k > N || a == NULL) { cou

寻找最小的k个数(四种方法)

1 使用从大到小的优先队列保存最小的K个数,每次取出K个数之后的其余数和堆顶元素比较,如果比堆顶元素小,则将堆顶元素删除,将该元素插入 void topK(int arr[],int n,int k) { if(k>n) return; priority_queue<int> q; for(int i=0;i<n;++i) { if(q.size()<k) q.push(arr[i]); else { if(arr[i]<q.top()) { q.pop(); q.pu

寻找最小的k个数(大顶堆方法)

题目描述:查找最小的k个元素,输入n个整数,输出其中最小的k个. 一般的排序方法,如快排,时间复杂度为O(n*logn+k); 大顶堆方法,时间复杂度为O(k+(n-k)*logk); 如果建立k个元素的最小堆的话,那么其空间复杂度势为O(N),而建立k个元素的最大堆的空间复杂度为O(k); 当面对海量数据处理的时候,大顶堆的方法是较为靠谱的,并且可以在面试时短时间内完成代码. 1 class Solution { 2 public: 3 void Swap(int &a,int &b)