最大堆(优先队列)基本概念,即一个完整建立,插入,删除代码

简介: 最大堆(优先队列)基本概念,即一个完整建立,插入,删除代码

堆(优先队列)priority queue

特殊的队列,取出元素的顺序是依照元素的优先权(关键字)大小,而出元素进入队列的先后顺序

操作:查找最大值(最小值),删除(最大值)

数组:

链表:

有序数组:

有序链表:

采用二叉搜索树? NO

采用完全二叉树 YES

堆的连个特性

结构性:用数组表示的完全二叉树:

有序性:任一结点的关键字是其字树所有结点的最大值(或最小值)

最大堆(MaxHeap)也称大顶堆:最大值

最小堆(MinHeap)也称“小顶堆”:最小值

从根节点到任意结点路径上结点序列的有序性

操作:插入任意一个元素,删除最 大值元素

最大堆的删除:取出根节点(最大值)元素,同时删除堆的一个结点

最大堆的建立:将已存在的N个元素按最大堆的要求存放在一个以为数组中

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 //最大堆
 4 
 5 #define MaxData 1000        //哨兵,该值应该根据具体情况定义为大于堆中所有可能元素的值
 6 
 7 typedef int ElementType;
 8 
 9 typedef struct HeapNode * MaxHeap;
10 struct HeapNode {
11     int Capacity;            //堆的最大容量
12     int Size;                //堆中当前元素个数
13     ElementType *Data;    //用于存储元素的数组
14 };

建一个空的最大堆:

 1 //建立一个空的最大堆
 2 MaxHeap InitHeap(int maxsize)
 3 {
 4     MaxHeap H = (MaxHeap)malloc(sizeof(struct HeapNode));
 5     H->Data = (ElementType*)malloc(sizeof(struct HeapNode) * (maxsize + 1));        //堆中的元素是从下标为1开始存储的,但是为了保证这个堆能存下maxsize个元素,所以要分配maxsize + 1个内存单元
 6     H->Capacity = maxsize;
 7     H->Size = 0;
 8     H->Data[0] = MaxData;            //将0下标的单元存储哨兵
 9     for (int i = 1; i < maxsize + 1; i++)
10         H->Data[i] = 0;
11     return H;
12 }

判断堆是否已满或是否为空:

 1 int IsEmpty(MaxHeap H)
 2 {
 3     return H->Size == 0;
 4 }
 5 
 6 //判断堆是否已满
 7 int IsFull(MaxHeap H)
 8 {
 9     return H->Size == H->Capacity;
10 }

插入一个元素:

 1 //最大堆中插入一个元素
 2 void Insert(MaxHeap H, ElementType item)
 3 {
 4     int i;
 5     if (IsFull(H))
 6     {
 7         printf("The heap is full\n");
 8         return;
 9     }
10     i = ++H->Size;        //i为插入后堆中最后一个元素的位置
11     for (; H->Data[i / 2] < item; i /= 2)
12         H->Data[i] = H->Data[i / 2];        //循环退出时,父节点的数据已经大于item, item已经找到了正确的位置
13     H->Data[i] = item;    //将item赋给正确的下标单元
14 }

删除一个元素:

 1 ElementType Delete(MaxHeap H)
 2 {
 3     ElementType temp, Max;
 4     int parent = 1, child;
 5     if (IsEmpty(H))
 6     {
 7         printf("The heap is empty!\n");
 8         return 0;
 9     }
10     Max = H->Data[1];            //现将最大值即根节点的值记录下来
11     temp = H->Data[H->Size--];        //用最后的结点元素暂时代替根节点的数据,然后将堆的数据大小减1
12 
13     //如果2 * parent > 0,那么说明parent已经是根节点了
14     for (; 2 * parent <= H->Size; parent = child)
15     {
16         child = 2 * parent;
17 
18         //如果Child != H->Size说明child不是最后一个结点,该parent结点还有右节点,
19         //并且如果右节点的值大于左结点,那么child++;
20         if (child != H->Size && (H->Data[child + 1] < H->Data[child]))
21             child++;        //child指向左右子节点的较大者
22         if (temp > H->Data[child]) break;            //如果孩子结点已经小于temp了, 说明找到了合适的位置
23         else
24             H->Data[parent] = H->Data[child];
25     }
26     H->Data[parent] = temp;
27     return Max;
28 }

最大堆的建立:

1.第一步,将N个元素按输入顺序存入二叉树中,这一步需要求满足完全二叉树的结构特性,而不管其有序性

2.从最后一个右孩子的结点开始调整,做类似删除元素时的下滤操作,逐个结点调整,直至根节点

 1 //创建一个最大堆
 2 MaxHeap CreateMaxHeap()
 3 {
 4     int dt, i = 0, j;
 5     int parent, child;
 6     ElementType X;
 7     MaxHeap H = InitHeap(20);        //先创建一个空的最大堆,然后往里面填充元素
 8     while (scanf_s("%d", &dt) != EOF)
 9     {
10         H->Data[i + 1] = dt;
11         i++;
12         H->Size++;
13     }
14     for (j = i / 2; j >= 1; j--)        //从i / 2开始逐一向下过滤
15     {
16         //下面的操作和删除元素是一模一样的,只是不用将的元素个数减一
17         X = H->Data[j];
18         for (parent = j; 2 * parent <= H->Size; parent = child)
19         {
20             child = 2 * parent;
21             if (child != H->Size && H->Data[child] < H->Data[child + 1])
22                 child++;
23             if (H->Data[child] < X)
24                 break;
25             else
26                 H->Data[parent] = H->Data[child];
27         }
28         H->Data[parent] = X;
29     }
30     return H;
31 }

打印堆中的元素:

1 //打印堆中元素
2 void printHeap(MaxHeap H)
3 {
4     for (int i = 1; i <= H->Size; i++)
5         printf("%d ", H->Data[i]);
6     printf("\n");
7 }

先序建立树:

 1 void PreOrderCreateHeap(MaxHeap H, int index)
 2 {
 3     int dt;
 4     scanf_s("%d", &dt);
 5     if (dt == 0)
 6     {
 7         return;
 8     }
 9     H->Size++;
10     H->Data[index] = dt;
11     printf("please enter the left child of %d :", dt);
12     PreOrderCreateHeap(H, 2 * index);
13     printf("please enter the right child of %d: ", dt);
14     PreOrderCreateHeap(H, 2 * index + 1);
15 }

主函数:

1 int main()
2 {
3     MaxHeap H = CreateMaxHeap();
4     PreOrderCreateHeap(H, 1);
5     printHeap(H);
6 
7     return 0;
8 }
相关文章
|
12月前
|
存储 索引
数据结构各结构特点(数组、链表、栈、队列、树)(上)
数据结构各结构特点(数组、链表、栈、队列、树)
188 0
|
2月前
数据结构堆排序中堆的建立、调整、插入、删除等操作的详解(题目讲解 简单易懂)
数据结构堆排序中堆的建立、调整、插入、删除等操作的详解(题目讲解 简单易懂)
155 0
|
1天前
|
算法 Java 调度
优先队列在数据结构中的作用与实现方式
优先队列在数据结构中的作用与实现方式
|
27天前
|
存储
数据结构学习记录——堆的插入(堆的结构类型定义、最大堆的创建、堆的插入:堆的插入的三种情况、哨兵元素)
数据结构学习记录——堆的插入(堆的结构类型定义、最大堆的创建、堆的插入:堆的插入的三种情况、哨兵元素)
14 2
|
12月前
|
存储
数据结构各结构特点(数组、链表、栈、队列、树)(下)
数据结构各结构特点(数组、链表、栈、队列、树)(下)
88 0
数据结构(7)树形结构——红黑树(概念、插入过程、删除过程)
7.1.概述 平衡二叉树是要求任意结点的左右子树高度差不超过1,因此在AVL中用旋转来保证树的绝对平衡,但是这些旋转操作步骤繁多很耗时间,所以在面对经常会有数据插入的场景时,AVL不是一个性能优秀的选择。这时候反过来思考一个问题,旋转是为了保证树的绝对平衡,但是树的绝对平衡是必须的吗?显然不是,树的高度差只要不是太高从而退化成斜二叉树其实就能接受。
68 0
|
C++
数据结构--栈相关操作的代码:
数据结构--栈相关操作的代码:
58 0
|
存储
大话数据结构--初始栈
大话数据结构--初始栈
59 0
|
存储 人工智能 算法
数据结构—线性表的定义与基本操作【插入、删除、查找】(下)
数据结构—线性表的定义与基本操作【插入、删除、查找】
405 0
数据结构—线性表的定义与基本操作【插入、删除、查找】(下)
|
存储 人工智能 Java
数据结构—线性表的定义与基本操作【插入、删除、查找】(上)
数据结构—线性表的定义与基本操作【插入、删除、查找】
480 0
数据结构—线性表的定义与基本操作【插入、删除、查找】(上)