zoukankan      html  css  js  c++  java
  • 数据结构:堆

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

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

    特性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
  • 相关阅读:
    错误解决mysql
    (一)熟悉执行流程——基于ThinkPHP3.2的内容管理框架OneThink学习
    版权控制之zend guard 6.0使用教程
    IP进制站群原理
    多线程更新已排序的Datagridview数据,造成数据错位
    压缩html 减小存储空间
    DataGridView导入导出excel
    软件下载目录
    java反射
    JTA
  • 原文地址:https://www.cnblogs.com/haoliuhust/p/4371199.html
Copyright © 2011-2022 走看看