堆排序及拓展

set

  1. 请写出堆排序的代码。
  2. 输入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     

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/wangpengjie/archive/2013/04/07/3003974.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞