接着昨天的写,里面的代码包含昨天的
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 }