优先队列及其基本操作的堆实现

用代码说话

/*
	本代码实现优先队列:分为最大优秀队列和最小优先队列
	优先队列用于维护一组元素构成的集合S的数据结构,其中的
	每一个元素都有一个相关的值,称为关键字。
	一个最大优先队列支持以下操作:
		insert(S,x)向S中插入元素x;
		maximum(S)返回S中的最大键值元素;
		extract-max(S)去掉并且返回S中的最大键值元素;
		increase-key(S,x,k)将元素x的关键字增加到k,假设k要不小于x的原关键字

	一个最小优先队列支持以下操作:
		insert(S,x)向S中插入元素x;
		minimum(S)返回S中的最小键值元素;
		extract-min(S)去掉并且返回S中的最小键值元素;
		decrease-key(S,x,k)将元素x的关键字减小到k,假设k要不大于x的原关键字

	最大优先队列可以应用与操作系统的作业调度
	最小优先队列可以用于基于事件驱动的模拟器
	本文将实现最大优先队列
	优先队列可以用堆来实现
*/

#include<stdio.h>
#include<stdlib.h>
#define N 6

static int heapSize=N;
/*
    返回父节点和子节点索引
*/
//返回父结点
int parent(int index)
{
    return (index-1)/2;
}

//返回左孩子
int left(int index)
{
    return (index<<1)+1;
}

//返回右孩子
int right(int index)
{
    return (index+1)<<1;
}

/*
    维护堆的性质,即把不符合要求的元素重新组织
    时间复杂度为logn
*/
int maxHeapify(int *A,int index,int size)
{
    int L=left(index);
    int R=right(index);
    int tmp;
    int largestIndex;
    if(L<size && *(A+index)<*(A+L)) {
        largestIndex=L;
    } else {
	largestIndex=index;
    }
    if(R<size && *(A+largestIndex)<*(A+R)) {
        largestIndex=R;
    }
    if(index!=largestIndex) {
        tmp=*(A+index);
        *(A+index)=*(A+largestIndex);
        *(A+largestIndex)=tmp;
        maxHeapify(A,largestIndex,size);
    }
    return 0;
}

/*
    对除没有子结点的结点进行堆的维护操作,进而
    使得一个数组变成一个最大堆
    时间复杂度为nlogn
*/
int buildMaxHeap(int *A)
{
    int size=N;
    //找出不是叶子结点的最后一个索引
    int need=heapSize/2-1;
    int i;
    for(i=need;i>=0;i--) {
        maxHeapify(A,i,heapSize);
    }
    return 0;
}

/*
    堆排序程序
    通过根元素始终是最大的,因此我们倒过来找
    从最大的元素依次往最小的元素去排序
*/
int heapSort(int *A)
{
    buildMaxHeap(A);
    int j;
    int size=heapSize;
    int i;
    int tmp;
    for(i=N-1;i>=1;i--) {
        tmp=*A;
        *A=*(A+i);
        *(A+i)=tmp;
        size--;
        maxHeapify(A,0,size);
    }
    return 0;
}

//------------------以下为优先队列的操作-----------------------//

/*
	返回堆的最大值
*/
int heapMaxElement(int *A)
{
	return A[0];
}

/*
	获取堆的最大值并移除该最大值
*/
int heapExtractMax(int *A)
{
	if(N<1) {
		printf("Heap error!");
	}
	int max=heapMaxElement(A);
	A[0]=A[heapSize-1];
	heapSize=heapSize-1;
	maxHeapify(A,0,heapSize);
	return max;
}

/*
	增加第i个元素的值,然后重新构建堆
*/
int heapIncreaseKey(int *A,int index,int newValue)
{
	if(newValue<*(A+index)) {
		printf("新增加的值应该要比原值大!");
		return 1;
	}
	*(A+index)=newValue;
	while(index>0&&*(A+index)>*(A+parent(index))) {
		int temp;
		temp=*(A+index);
		*(A+index)=*(A+parent(index));
		*(A+parent(index))=temp;
		index=parent(index);
	}
	return 0;
}

/*
	向最大堆中插入元素
*/
int heapInsert(int *A,int key)
{
	heapSize=heapSize+1;
	int *b=malloc(sizeof(int)*heapSize);
	b=A;
	*(b+heapSize-1)=key-1;
	heapIncreaseKey(b,heapSize-1,key);
	A=b;
	return 0;
}

int main()
{
	int b[N]={2,1,3,2,5,4};
	int* a=b;
	//必做:构建最大堆
	buildMaxHeap(a);
	printf("增加第一个元素的值为6\n");
	heapIncreaseKey(a,0,6);
	printf("%d\n",*a); 

	printf("向堆中插入7\n");
	heapInsert(a,7);
	printf("%d\n",*a); 

	printf("输出顶部元素\n");
	printf("%d\n",*a);

	printf("弹出顶部元素\n");
	printf("%d\n",heapExtractMax(a));

	printf("输出顶部元素\n");
	printf("%d\n",*a);

	return 0;
}

运行结果

[email protected]:~/Algorithms/chap6/demo1$ ./priorityQueue
增加第一个元素的值为6
6
向堆中插入7
7
输出顶部元素
7
弹出顶部元素
7
输出顶部元素
6
时间: 2024-07-30 10:18:03

优先队列及其基本操作的堆实现的相关文章

优先队列之二叉堆与d-堆

二叉堆简介 平时所说的堆,若没加任何修饰,一般就是指二叉堆.同二叉树一样,堆也有两个性质,即结构性和堆序性.正如AVL树一样,对堆的以此操作可能破坏者两个性质中的一个,因此,堆的操作必须要到堆的所有性质都被满足时才能终止. 结构性质 堆是一棵完全填满的二叉树,因为完全二叉树很有规律,所以它可以用一个数组表示而不需要指针.如下图所示,图2中的数组对应图1中的堆.                   图1:二叉堆                                            

算法学习 - 优先队列的二叉堆实现

PriorityQuenue 优先队列就是作业调度类的ADT,这里用二叉堆来实现. 优先队列最少有两个操作:插入(Insert)和删除最小者(DeleteMin). 插入操作图解: 图片来源:www.educity.cn 删除操作图解: 图片来源:www.cfanz.cn 代码实现: // // main.cpp // binaryHeap // // Created by Alps on 14-8-17. // Copyright (c) 2014年 chen. All rights rese

优先队列底层实现是堆(heap)(操作系统进程调度)

只有一个CPU的情况下,比如作业系统中的调度程序,当一个作业完成后,需要在所有等待调度的作业中选择一个优先级最高的作业来执行(删除),并且也可以添加一个新的作业到作业的优先队列中(插入). 插入操作 插入操作是将一个元素插入到队列的尾部,然后执行"上浮"操作(调整为堆) 删除操作 优先队列中,在队列非空情况下移除集合中第一个元素,也就是下标为0的元素,然后将集合中最后一个元素移到下标为0位置,在将下标为0的新元素执行"下沉"操作

《Algorithms算法》笔记:优先队列(2)——二叉堆

二叉堆 1 二叉堆的定义 堆是一个完全二叉树结构(除了最底下一层,其他层全是完全平衡的),如果每个结点都大于它的两个孩子,那么这个堆是有序的. 二叉堆是一组能够用堆有序的完全二叉树排序的元素,并在数组中按照层级存储(不用数组的第一个位置) 2 二叉堆的性质 最大的元素在a[1] (root结点) 每个k的父亲在k/2 每个k的孩子在k*2和k*2+1 3 二叉堆的操作 3.1 上浮(孩子大于父亲)--对应插入操作 循环,每次比较自己和父亲,如果比父亲大就交换,直到root. 3.2 插入 先把元

优先队列Priority Queue和堆Heap

对COMP20003中的Priority queue部分进行总结.图片来自于COMP20003 queue队列,顾名思义特点先进先出 priority queue优先队列,出来的顺序按照优先级priority大小,越大(小)的先pop. 普通的方法: Unsorted array: Construct: O(n) Get highest priority: O(n) Sorted array: Construct: O(n2) Get highest priority: O(1) 使用堆heap

支持删除任意元素以及一些其他基本操作的堆

一个黑科技,不知道是谁发明的(好像也有些年代了?) 其实这个黑科技的本质就是一个大根堆,不同的是 它支持删除堆内任意元素,同时也支持堆的基本操作 code 代码如下: struct Heap{ priority_queue<int> q1,q2; inline void push(int x){q1.push(x);} inline void erase(int x){q2.push(x);} inline void pop(){for(;q2.size()&&q1.top()

算法导论学习之堆+堆排序+堆构成优先队列

注:堆分为最大堆和最小堆两种,下面我们讨论的堆都是指的最大堆,最小堆的性质与其是类似的. 堆数据结构是一种数组对象,可以被视为一棵完全二叉树(这棵二叉树除最后一层外,其余每层都是填满的):我们用一个数组来存储一个堆,表示堆的数组有两个属性:length[A]表示的是数组中的元素个数,headsize[A]表示堆中元素个数(也就是说数组中的元素不一定都是堆中的元素). 下面不加证明的给出一些堆的性质: 对于任何一个节点,其父节点为i/2(i>1):左儿子:2*i,右儿子:2*i+1; 对于最大堆每

优先队列及最小堆最大堆

为什么优先队列里默认是堆(heap)实现,默认是优先级高的出队,定义结构体重载函数为什么要按照从小到大排序?原来是自己对优先队列还不太了解: 1 堆 1.1 简介 n个关键字序列Kl,K2,-,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质): (1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),当然,这是小根堆,大根堆则换成>=号.//k(i)相当于二叉树的非叶结点,K(2i)则是左孩子,k(2i+1)是右孩子 若将此序列所存储的向量R[1..n]看做是一

优先队列及(二叉)堆

数据结构书籍与算法书(包括算法导论.算法设计)通常将优先队列(Priority Queue)与堆(Heap)放在一起讲,算法导论上先讲堆这个特殊的数据结构,后讲堆的两个应用,堆排序与优先队列.算法设计这本书先讲优先队列是个什么样的数据结构,有什么性质,为什么需要优先队列这种数据结构,然后讲实现优先队列有什么样的要求,而这些要求数组(Array)和链表(Linked List)都不能满足,所以我们需要设计一种新的数据结构来满足这些要求,那就是堆.个人更喜欢算法设计书上这种顺序. 某些特定的算法,只