数据结构:堆

堆是一种优先队列的实现。堆是一颗完全二叉树,所谓完全二叉树就是除了最后一层以外,其他层都是满的,而且最后一层所缺的叶结点都在右边。

在完全二叉树中,节点的序列号有如下关系:

特性4:设完全二叉树中一元素的序号为i,1<=i<=n.则有以下关系:

当i=1时,节点为树的根。若i>1,则该元素父节点为i/2(向下取整)

当2*i>n时,该元素无左孩子。否则,其左孩子为2*i。

当2*i+1>n时,无右孩子。否则,右孩子为2*i+1。

可以用公式化描述的树来高效存储完全二叉树。

1.定义

最大树:每个节点的值都大于或等于其子节点(如果有的话)值得树。(最大树可以多于二叉)

最大堆:最大的完全二叉树

由于堆是完全的二叉树,因而可以利用它的这一特性方便的用数组实现堆。

2.最大堆的插入

插入时,从最后一个元素向根结点方向搜索,找到对应的位置插入。O(log2n)

3.最大堆的删除

删除根结点,然后将最后一个叶结点放入根结点,并向下搜索,找到对应位置插入。O(log2n)

4.最大堆的初始化

可以用n个数组元素初始化最大堆。初始化的过程可以分为n个插入操作,所需时间为O(nlogn)。或者用下面这种方式,时间为O(n)

从第一个具有孩子的节点开始(即节点 n),这个元素在数组中的位置为 i = [n / 2 ],如果以这个元素为根的子树已是最大堆,则此时不需调整,否则必须调整子树使之成为堆。随后,继续检查以 i-1, i-2等节点为根的子树,直到检查到整个二叉树的根节点(其位置为1)。

 

5.实现

类定义:

 1 template<typename T>
 2 class MaxHeap
 3 {
 4 public:
 5     MaxHeap(int MaxHeapSize = 10);
 6     ~MaxHeap()
 7     {
 8         if (heap!=NULL)
 9         {
10             delete[] heap;
11             heap = NULL;
12         }
13     }
14 
15     int Size() const{ return CurrentSize; }
16     T Max()
17     {
18         if (CurrentSize==0)
19         {
20             throw OutofBounds();
21         }
22 
23         return heap[1];
24     }
25 
26     MaxHeap<T>& Insert(const T& x);
27     MaxHeap<T>& DeleteMax(T& x);
28     void Initialize(T a[], int size, int ArraySize);
29 private:
30     int CurrentSize;
31     int MaxSize;
32     T* heap;
33 };
View Code

操作:

 1 template<typename T>
 2 MaxHeap<T>::MaxHeap(int MaxHeapSize=10):MaxSize(MaxHeapSize),CurrentSize(0)
 3 {
 4     heap = new T[MaxSize + 1];
 5 }
 6 
 7 template<typename T>
 8 MaxHeap<T>& MaxHeap<T>::Insert(const T& x)
 9 {
10     size_t index = ++CurrentSize;
11     //从最后一个叶结点向上搜索,找到对应的位置
12     while (index!=1&&x>heap[index/2])
13     {
14         
15         heap[index] = heap[index / 2];//父结点下移
16         index = index / 2;//移向父节点
17     }
18 
19     heap[index] = x;
20 
21     return *this;
22 }
23 
24 template<typename T>
25 MaxHeap<T>& MaxHeap<T>::DeleteMax(T& x)
26 {
27     if (CurrentSize==0)
28     {
29         throw OutofBounds();
30     }
31 
32     x = heap[1];
33     T temp = heap[CurrentSize--];
34     size_t index = 1;//父节点
35     size_t cindex = 2;//子节点
36 
37     while(cindex<=CurrentSize)
38     {
39         //找到左右子节点的大值
40         if (cindex<CurrentSize&&heap[cindex]<heap[cindex+1])
41         {
42             ++cindex;
43         }
44         //如果当前点大于子节点,插入此处子节点的父节点
45         if (temp>=heap[cindex])
46         {
47             break;
48         }
49 
50         heap[index] = heap[cindex];//父节点向下移
51         index = cindex;//父节点向下移
52         cindex *= 2;//子节点下移
53     }
54 
55     heap[index] = temp;
56     return *this;
57 }
58 
59 template<typename T>
60 void MaxHeap<T>::Initialize(T a[], int size, int ArraySize)
61 {
62     delete[] heap;
63     heap = new T[ArraySize + 1];
64     MaxSize = ArraySize;
65     CurrentSize = size;
66 
67     memcpy(heap+1, a, (CurrentSize)*sizeof(T));
68     size_t cindex;
69     /************************************************************************/
70     /*从第一个具有孩子的节点开始(即节点 n),
71     这个元素在数组中的位置为 i = [n / 2 ],
72     如果以这个元素为根的子树已是最大堆,则此时不需调整,否则必须调整子树使之成为堆。
73     随后,继续检查以 i-1, i-2等节点为根的子树,直到检查到整个二叉树的根节点(其位置为1)。*/
74     /************************************************************************/
75     for (size_t index = CurrentSize / 2; index >= 1;--index)
76     {
77         T temp = heap[index];
78 
79         cindex = 2 * index;
80         while (cindex<=CurrentSize)
81         {
82             if (cindex<CurrentSize&&heap[cindex + 1]>heap[cindex])
83             {
84                 ++cindex;
85             }
86 
87             if (temp>heap[cindex])
88             {
89                 break;
90             }
91 
92             heap[cindex/2] = heap[cindex];
93             cindex *= 2;
94         }
95         
96         heap[cindex / 2] = temp;        
97     }
98 
99 }
View Code

完整定义:

  1 #ifndef MAXHEAP_H
  2 #define MAXHEAP_H
  3 
  4 #include<iostream>
  5 #include<algorithm>
  6 #include "exceptionerror.h"
  7 using namespace std;
  8 
  9 template<typename T>
 10 class MaxHeap
 11 {
 12 public:
 13     MaxHeap(int MaxHeapSize = 10);
 14     ~MaxHeap()
 15     {
 16         if (heap!=NULL)
 17         {
 18             delete[] heap;
 19             heap = NULL;
 20         }
 21     }
 22 
 23     int Size() const{ return CurrentSize; }
 24     T Max()
 25     {
 26         if (CurrentSize==0)
 27         {
 28             throw OutofBounds();
 29         }
 30 
 31         return heap[1];
 32     }
 33 
 34     MaxHeap<T>& Insert(const T& x);
 35     MaxHeap<T>& DeleteMax(T& x);
 36     void Initialize(T a[], int size, int ArraySize);
 37 private:
 38     int CurrentSize;
 39     int MaxSize;
 40     T* heap;
 41 };
 42 
 43 template<typename T>
 44 MaxHeap<T>::MaxHeap(int MaxHeapSize=10):MaxSize(MaxHeapSize),CurrentSize(0)
 45 {
 46     heap = new T[MaxSize + 1];
 47 }
 48 
 49 template<typename T>
 50 MaxHeap<T>& MaxHeap<T>::Insert(const T& x)
 51 {
 52     size_t index = ++CurrentSize;
 53     //从最后一个叶结点向上搜索,找到对应的位置
 54     while (index!=1&&x>heap[index/2])
 55     {
 56         
 57         heap[index] = heap[index / 2];//父结点下移
 58         index = index / 2;//移向父节点
 59     }
 60 
 61     heap[index] = x;
 62 
 63     return *this;
 64 }
 65 
 66 template<typename T>
 67 MaxHeap<T>& MaxHeap<T>::DeleteMax(T& x)
 68 {
 69     if (CurrentSize==0)
 70     {
 71         throw OutofBounds();
 72     }
 73 
 74     x = heap[1];
 75     T temp = heap[CurrentSize--];
 76     size_t index = 1;//父节点
 77     size_t cindex = 2;//子节点
 78 
 79     while(cindex<=CurrentSize)
 80     {
 81         //找到左右子节点的大值
 82         if (cindex<CurrentSize&&heap[cindex]<heap[cindex+1])
 83         {
 84             ++cindex;
 85         }
 86         //如果当前点大于子节点,插入此处子节点的父节点
 87         if (temp>=heap[cindex])
 88         {
 89             break;
 90         }
 91 
 92         heap[index] = heap[cindex];//父节点向下移
 93         index = cindex;//父节点向下移
 94         cindex *= 2;//子节点下移
 95     }
 96 
 97     heap[index] = temp;
 98     return *this;
 99 }
100 
101 template<typename T>
102 void MaxHeap<T>::Initialize(T a[], int size, int ArraySize)
103 {
104     delete[] heap;
105     heap = new T[ArraySize + 1];
106     MaxSize = ArraySize;
107     CurrentSize = size;
108 
109     memcpy(heap+1, a, (CurrentSize)*sizeof(T));
110     size_t cindex;
111     /************************************************************************/
112     /*从第一个具有孩子的节点开始(即节点 n),
113     这个元素在数组中的位置为 i = [n / 2 ],
114     如果以这个元素为根的子树已是最大堆,则此时不需调整,否则必须调整子树使之成为堆。
115     随后,继续检查以 i-1, i-2等节点为根的子树,直到检查到整个二叉树的根节点(其位置为1)。*/
116     /************************************************************************/
117     for (size_t index = CurrentSize / 2; index >= 1;--index)
118     {
119         T temp = heap[index];
120 
121         cindex = 2 * index;
122         while (cindex<=CurrentSize)
123         {
124             if (cindex<CurrentSize&&heap[cindex + 1]>heap[cindex])
125             {
126                 ++cindex;
127             }
128 
129             if (temp>heap[cindex])
130             {
131                 break;
132             }
133 
134             heap[cindex/2] = heap[cindex];
135             cindex *= 2;
136         }
137         
138         heap[cindex / 2] = temp;        
139     }
140 
141 }
142 #endif
View Code

6.应用:堆排序,复杂度O(nlogn)

步骤:

1.用待排序数组初始化最大堆(最小堆)O(n)

2.从堆中逐一取出元素即可组成有序的堆O(logn)

 1 #include<iostream>
 2 #include "MaxHeap.h"
 3 using namespace std;
 4 
 5 void HeapSort(int a[],int n)
 6 {
 7     if (a == NULL||n<=0)
 8     {
 9         throw exception("Invalid input");
10     }
11 
12     MaxHeap<int> H(1);
13     H.Initialize(a, n, n);
14 
15     for (int i = 0; i < n;++i)
16     {
17         H.DeleteMax(a[i]);
18     }
19 }
20 
21 
22 int main()
23 {
24     int a[] = { 0, 3, 4, 6, 0, 5, 8, 9 };
25     cout << "Array to be sorted is:" << endl;
26     int length = sizeof(a) / sizeof(int);
27     for (int i = 0; i < length;++i)
28     {
29         cout << a[i] << ' ';
30     }
31     cout << endl;
32 
33     HeapSort(a, length);
34     cout << "After sort:" << endl;
35     for (int i = 0; i < length; ++i)
36     {
37         cout << a[i] << ' ';
38     }
39 
40     return 0;
41 }
View Code

 最小堆:

  1 #ifndef MinHeap_H
  2 #define MinHeap_H
  3 
  4 #include<iostream>
  5 #include<algorithm>
  6 #include "exceptionerror.h"
  7 using namespace std;
  8 
  9 template<typename T>
 10 class MinHeap
 11 {
 12 public:
 13     MinHeap(int MaxHeapSize = 10);
 14     ~MinHeap()
 15     {
 16         if (heap!=NULL)
 17         {
 18             delete[] heap;
 19             heap = NULL;
 20         }
 21     }
 22 
 23     int Size() const{ return CurrentSize; }
 24     T Min()
 25     {
 26         if (CurrentSize==0)
 27         {
 28             throw OutofBounds();
 29         }
 30 
 31         return heap[1];
 32     }
 33 
 34     MinHeap<T>& Insert(const T& x);
 35     MinHeap<T>& DeleteMin(T& x);
 36     void Initialize(T a[], int size, int ArraySize);
 37 private:
 38     int CurrentSize;//堆中元素的个数
 39     int MaxSize;//堆的最大容量
 40     T* heap;
 41 };
 42 
 43 template<typename T>
 44 MinHeap<T>::MinHeap(int MaxHeapSize=10):MaxSize(MaxHeapSize),CurrentSize(0)
 45 {
 46     heap = new T[MaxSize + 1];//元素从1开始存储
 47 }
 48 
 49 //从叶结点往上移
 50 template<typename T>
 51 MinHeap<T>& MinHeap<T>::Insert(const T& x)
 52 {
 53     size_t index = ++CurrentSize;//从新的叶结点开始,沿树上升
 54     while (index!=1&&x<heap[index/2])
 55     {
 56         heap[index] = heap[index / 2];//元素下移
 57         index = index / 2;//移向父节点
 58     }
 59 
 60     heap[index] = x;
 61 
 62     return *this;
 63 }
 64 
 65 template<typename T>
 66 MinHeap<T>& MinHeap<T>::DeleteMin(T& x)
 67 {
 68     if (CurrentSize==0)
 69     {
 70         throw OutofBounds();
 71     }
 72 
 73     x = heap[1];//最小值
 74     T temp = heap[CurrentSize--];//最后一个叶结点值,找到它的待插位置
 75     size_t index = 1;
 76     size_t cindex = 2;
 77     while(cindex<=CurrentSize)
 78     {
 79         if (cindex<CurrentSize&&heap[cindex]>heap[cindex+1])//找到左右节点的最小值
 80         {
 81             ++cindex;
 82         }
 83         //是否找到位置
 84         if (temp<heap[cindex])
 85         {
 86             break;
 87         }
 88         
 89         heap[index] = heap[cindex];//未找到,move down
 90         index = cindex;
 91         cindex *= 2;
 92     }
 93 
 94     heap[index] = temp;
 95     return *this;
 96 }
 97 
 98 /************************************************************************/
 99 /* 从第一个具有孩子的节点开始
100 这个元素在数组中的位置为 i = [n / 2 ],如果以这个元素为根的子树已是最大堆,则此时不需调
101 整,否则必须调整子树使之成为堆。随后,继续检查以 i-1, i-2等节点为根的子树,直到检查
102 到整个二叉树的根节点(其位置为1)。                                                                     */
103 /************************************************************************/
104 
105 template<typename T>
106 void MinHeap<T>::Initialize(T a[], int size, int ArraySize)
107 {
108     delete[] heap;
109     heap = new T[ArraySize + 1];
110     MaxSize = ArraySize;
111     CurrentSize = size;
112 
113     memcpy(heap+1, a, (CurrentSize)*sizeof(T));
114     size_t cindex;
115     for (size_t index = CurrentSize / 2; index >= 1;--index)
116     {
117         T temp = heap[index];
118 
119         cindex = 2 * index;
120         while (cindex<=CurrentSize)
121         {
122             if (cindex<CurrentSize&&heap[cindex + 1]<heap[cindex])
123             {
124                 ++cindex;
125             }
126 
127             if (temp<heap[cindex])
128             {
129                 break;
130             }
131 
132             heap[cindex/2] = heap[cindex];
133             cindex *= 2;
134         }
135         
136         heap[cindex / 2] = temp;        
137     }
138 
139 }
140 #endif
View Code

 

posted @ 2015-03-27 11:08  CoderInCV  阅读(298)  评论(0编辑  收藏  举报