数据结构-----堆的基本操作和应用

(一)用仿函数实现大堆小堆

堆数据结构是一种数组对象,它可以被视为一棵完全二叉树结构。

堆结构的二叉树存储是

最大堆:每个父节点的都大于孩子节点。

最小堆:每个父节点的都小于孩子节点。

仿函数(functor),就是使一个类的使用看上去象一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了。
在实现大,小堆的过程中,有些功能的的代码,会在不同的成员函数中用到,想复用这些代码,有两种途径。

1)公共的函数,这是一个解决方法,不过函数用到的一些变量,就可能成为公共的全局变量,再说为了复用这么一片代码,就要单立出一个函数,也不是很好维护。

2)仿函数,写一个简单类,除了那些维护一个类的成员函数外,就只是实现一个operator(),在类实例化时,就将要用的,非参数的元素传入类中。

在C++里,我们通过在一个类中重载括号运算符的方法使用一个函数对象而不是一个普通函数

Heap.h

#include <iostream>  
#include <algorithm>  
  
using namespace std;  
template<typename T>  
class display  
{  
public:  
    void operator()(const T &x)  
    {  
        cout<<x<<" ";   
    }   
};   
  
  
int main()  
{  
    int ia[]={1,2,3,4,5};  
    for_each(ia,ia+5,display<int>());   
      
    return 0;   
}

用仿函数实现大堆,小堆的基本结构

#include<iostream>
#include<vector>
using namespace std;

template<class T>
struct Less//小于
{
	bool operator()(const T&l,const T&r)
	{
	return l<r;
	}
};

template<class T>
struct Greater
{
	bool operator()(const T&l,const T&r)
	{
	return l>r;
	}
};
template<class T,class Comper=Greater<T>>//默认建大堆
class Heap
{
private:
	vector<T> _a;
public:

	Heap(const T* a,size_t size)
	{
		assert(a);
		//将数组中的数据压入栈中
		for(i=0;i<size;i++)
		{
		_a.push_back(a[i]);
		}
		//建大堆
		for(int i=(_a.size()-2)/2;i>=0;i--)
		{
		//向下调整
		_AdjustDown(i);
		}
	}
	//向堆中插入数据
	void push(const T& x)
	{
	_a.push_back (x);
	_Adjustup(_a.size()-1)
	}
/********************
在弹出的时候使用的方法是
先将完全二叉树的根节点与最后一个叶子节点交换,
弹出当前的叶子节点,然后在向下调整
************************/
	void pop()
	{
	swap(_a[0],_a[_a.size()-1]);
	_a.pop_back ();
	_AdjustDown(0);
	}
	size_t Size()//求堆的大小
	{
	  return _a.size();
	}

	bool Empty()//堆是否为空
	{
	return _a.empty();
	}
protected:
	void _AdjustDown(size_t parent)
	{
		size_t child=2*parent+1;
		while(child<_a.size())
		{
			Comper com;
			//找出两个孩子中最大的一个
			if(com(_a[child+1],_a[child]) && child+1<_a.size())//因为是完全二叉树所以右孩子可能不存在
			{
			child=child+1;
			}
			//如果孩子大于父亲则交换继续往下调整
			if(com(_a[child],_a[parent]))
			{
			swap(_a[child],_a[parent]);
			parent=child;
			child=2*parent+1;
			}
			//否则满足大根堆,退出循环
			else
			{
			break;
			}
		}

	}

	//向上调整
	void _Adjustup(size_t child)
	{
		 size_t parent=(child-1)/2;
		 while(child>0)//不能写成while(parent>0),因为child为size_t 类型,会构成死循环
		 {
			 Comper com;
			 //如果插入的子节点大于根节点,则交换
			 if(com(_a[child],_a[parent]))
			 {
			 swap(_a[child],_a[parent]);
			 child=parent;
			 parent=(child-1)/2;
			 }
			 //否则满足大堆,退出循环
			 else
			 {
			 break;
			 }
		 }
	}
};

(二)堆排序

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<assert.h>
using namespace std;

//建初堆,大堆
void AdjustDown(int a[],int n,int parent)
{
	int child=parent*2+1;
	while(child<n)
	{
		if(child+1<n&&a[child]<a[child+1])
		{
		++child;
		}

		if(a[child]>a[parent])
		{
		swap(a[child],a[parent]);
		parent=child;
		child=parent*2+1;
		}
		else
		{
		break;
		}
	}
}

void HeapSort(int a[],int n)
{
	assert(a);
	//建大堆
	for(int i=(n-2)/2;i>=0;i--)
	{
	AdjustDown(a,n,i);
	}
	//选出一个数据交换到末尾,利用帅选法将前N-i个元素重新帅选建成一个堆
	for(int i=n-1;i>0;i--)
	{
	swap(a[0],a[i]);
	AdjustDown(a,i,0);
	}

}

void test()
{
	int a[8]={98,77,35,62,55,14,35,48};
	int size=sizeof(a)/sizeof(a[0]);
	HeapSort(a,size);
	for(int i=0;i<size;i++)
	{
	cout<<a[i]<<" ";

	}
	cout<<endl;
}
int main()
{
	test();
	system("pause");
	return 0;

}
时间: 2024-11-08 10:35:54

数据结构-----堆的基本操作和应用的相关文章

数据结构-堆

堆(英语:Heap),是一种拥有像树那样的特殊数据结构,或者理解为具有优先级的树.它的特点是父节点的值大于(或小于)两个子节点的值(分别称为大顶堆和小顶堆).它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等.堆通常是一个可以被看做一棵树的数组(或ArrayList)对象.常见的堆有二叉堆.二项堆.斐波那契堆等. 二叉堆(Binary heap) 二叉堆是一种特殊的堆,实为二叉树的一种:是完全二叉树或者是近似完全二叉树.二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子

基本数据结构——堆(Heap)的基本概念及其操作

基本数据结构――堆的基本概念及其操作 小广告:福建安溪一中在线评测系统 Online Judge 在我刚听到堆这个名词的时候,我认为它是一堆东西的集合... 但其实吧它是利用完全二叉树的结构来维护一组数据,然后进行相关操作,一般的操作进行一次的时间复杂度在 O(1)~O(logn)之间. 可谓是相当的引领时尚潮流啊(我不信学信息学的你看到log和1的时间复杂度不会激动一下下)!. 什么是完全二叉树呢?别急着去百度啊,要百度我帮你百度: 若设二叉树的深度为h,除第 h 层外,其它各层 (1-h-1

数据结构--堆的实现之深入分析

一,介绍 以前在学习堆时,写了两篇文章:数据结构--堆的实现(上)   和   数据结构--堆的实现(下),  感觉对堆的认识还是不够.本文主要分析数据结构 堆(讨论小顶堆)的基本操作的一些细节,比如 insert(插入)操作 和 deleteMin(删除堆顶元素)操作的实现细节.分析建堆的时间复杂度.堆的优缺点及二叉堆的不足. 二,堆的实现分析 堆的物理存储结构是一维数组,逻辑存储结构是完全二叉树.堆的基本操作有:insert--向堆中插入一个元素:deleteMin--删除堆顶元素 故堆的类

【C/C++学院】0828-STL入门与简介/STL容器概念/容器迭代器仿函数算法STL概念例子/栈队列双端队列优先队列/数据结构堆的概念/红黑树容器

STL入门与简介 #include<iostream> #include <vector>//容器 #include<array>//数组 #include <algorithm>//算法 using namespace std; //实现一个类模板,专门实现打印的功能 template<class T> //类模板实现了方法 class myvectorprint { public: void operator ()(const T &

数据结构--堆的实现(下)

1,堆作为优先级队列的应用 对于普通队列而言,具有的性质为FIFO,只要实现在队头删除元素,在队尾插入元素即可.因此,这种队列的优先级可视为按 时间到达 的顺序来衡量优先级的.到达得越早,优先级越高,就优先出队列被调度. 更一般地,很多应用不能单纯地按时间的先后来分优先级,比如按CPU占用时间或者其它方式……在这种情形下,使用堆更容易表达优先级队列. 2,堆的两个性质:①结构性质--堆从结构上看是一颗完全二叉树.然而,从物理存储上看,堆的实现基本上是使用一个一维数组存储堆中所有的结点.②orde

C 数据结构堆

引言 - 数据结构堆 堆结构都很耳熟, 从堆排序到优先级队列, 我们总会看见它的身影. 相关的资料太多了, 堆 - https://zh.wikipedia.org/wiki/%E5%A0%86%E7%A9%8D 无数漂亮的图片接二连三, 但目前没搜到一个工程中可以舒服用的代码库. 本文由此痛点而来. 写一篇奇妙数据结构堆的终结代码. 耳熟终究比不过手热 ->--- 对于 heap 接口思考, 我是这样设计 #ifndef _H_HEAP #define _H_HEAP // // cmp_f

Redis数据结构之sds基本操作函数

本文及后续文章,Redis版本均是v3.2.8 本篇文章讲解sds基本操作函数,我们从源码角度来进一步理解. 一.sds创建函数和销毁 sds创建函数 /* Create a new sds string with the content specified by the 'init' pointer * and 'initlen'. * If NULL is used for 'init' the string is initialized with zero bytes. * * The s

浅谈数据结构-堆

在数据结构的世界中有一个叫堆的玩意,这玩意有什么用呢?无用,都去pq了 堆,其实就是一棵完全二叉树. “若设二叉树的深度为h,除第 h 层外,其它各层 (1-h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树”  by 谋财害命公司 百度 ↑清真的 完全二叉树 ↓ 啊那么为什么会闲的无聊出现这种奇怪的数据结构呢? 因为我们的某些算法可能需要堆来进行优化,如dj,prim. 堆可以在O(1)的时间取出最优值,但是需要O(logn)的时间修改和O(nlogn)

数据结构—堆

堆是二叉树中的一种,是一种常见的数据结构,具有以下性质: 任意节点小于(最小堆)或大于(最大堆)它的所有后裔,最小元或最大元在堆的根上(堆序性). 堆总是一棵完全二叉树 最大堆如图一,最小堆如图二. 最小堆的实现如下: MinHeap.h 1 #include "stdafx.h" 2 #include <iostream> 3 using namespace std; 4 template <typename Type> 5 class MinHeap{ 6