堆排序及拓展
set
- 请写出堆排序的代码。
- 输入n个整数,找出其中最小的k个数。
1、思路:
堆排序分为建堆(insertion)和取根数据(delete root)。每一步都涉及到堆调整,堆调整算法的时间复杂度为O(logn)。
HeapSort
1 #include <stdio.h> 2 3 #define heap_parent(npos) ((int)(((npos) - 1) / 2)) 4 #define heap_left(npos) ((npos) * 2 + 1) 5 #define heap_right(npos) ((npos) * 2 + 2) 6 7 void Swap(int *a, int *b) 8 { 9 int temp = *a; 10 *a = *b; 11 *b = temp; 12 } 13 14 void PrintArray(int data[], int length) 15 { 16 for (int i = 0; i < length; i++) 17 printf("%d ", data[i]); 18 printf("\n"); 19 } 20 21 //子树满足最大堆的性质,只要判断根与左右两节点大小,看根是否满足最大堆性质。 22 //如果根与左右某个节点互换位置,则可能破坏了子树的最大堆性质。 23 //直到根节点均大于左右子节点,或是到达叶子节点,循环结束。 24 void HeapAdjust(int data[], int node, int size) 25 { 26 while (heap_left(node) < size) 27 { 28 int temp = heap_left(node); 29 if (heap_right(node) < size) 30 { 31 if (data[heap_left(node)] < data[heap_right(node)]) 32 temp = heap_right(node); 33 } 34 if (data[node] < data[temp]) 35 { 36 Swap(&data[node], &data[temp]); 37 node = temp; 38 } 39 else 40 break; 41 } 42 } 43 44 void HeapSort(int data[], int size) 45 { 46 //由二叉树的下层往上层进行父子节点的数据比较,进行“筛选”调整堆的过程 47 //构建堆是从非叶子节点开始从下往上,调整堆是从上往下。 48 for (int i = size / 2 - 1; i >= 0; i--) 49 HeapAdjust(data, i, size); 50 51 //将根数据与末数据互换位置,始终调整根数据的最大堆性质,但是堆节点数量减少。 52 for (int i = size - 1; i > 0; i--) 53 { 54 Swap(&data[0], &data[i]); 55 HeapAdjust(data, 0, i); 56 } 57 } 58 59 int main() 60 { 61 int test[10] = {3, 5, 6, 4, 8, 0, 2, 7, 1, 9}; 62 PrintArray(test, 10); 63 HeapSort(test, 10); 64 PrintArray(test, 10); 65 }
2、思路:
如果可以用STL的话,我们可以选择允许增序的关联容器multiset,实现是红黑树方法,插入和删除都是O(logk)的时间复杂度,取最大元素是O(1)的时间复杂度。
GetKLeastNumbers
1 #include <iostream> 2 #include <vector> 3 #include <set> 4 5 using namespace std; 6 7 typedef multiset<int, greater<int> > setK; 8 typedef multiset<int, greater<int> >::iterator sIter; 9 10 void GetKLeastNumbers(const vector<int>& data, setK& leastNumbers, int k) 11 { 12 leastNumbers.clear(); 13 if (k < 1 || data.size() < k) return; 14 15 for (vector<int>::const_iterator iter = data.begin(); iter != data.end(); iter++) 16 { 17 if (leastNumbers.size() < k) 18 leastNumbers.insert(*iter); 19 else 20 { 21 sIter topK = leastNumbers.begin(); 22 if (*iter < *topK) 23 { 24 leastNumbers.erase(topK); 25 leastNumbers.insert(*iter); 26 } 27 } 28 } 29 } 30 31 void Test(char* testName, int* data, int n, int* expectedResult, int k) 32 { 33 if (testName != NULL) 34 printf("%s\n", testName); 35 36 vector<int> vData; 37 for (int i = 0; i < n; i++) 38 vData.push_back(data[i]); 39 40 if (expectedResult == NULL) 41 printf("We don't expect any result!\n"); 42 else 43 { 44 printf("Expected result:\n"); 45 for (int i = 0; i < k; i++) 46 printf("%d\t", expectedResult[i]); 47 printf("\n"); 48 } 49 50 setK leastNumbers; 51 GetKLeastNumbers(vData, leastNumbers, k); 52 printf("The actual output numbers are:\n"); 53 for (sIter iter = leastNumbers.begin(); iter != leastNumbers.end(); iter++) 54 printf("%d\t", *iter); 55 printf("\n"); 56 } 57 58 int main() 59 { 60 int data[] = {4, 5, 1, 6, 2, 7, 3, 8}; 61 int expected[] = {1, 2, 3, 4}; 62 Test("test1", data, sizeof(data) / sizeof(int), expected, sizeof(expected) / sizeof(int)); 63 } 64 65