溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

數(shù)據(jù)結(jié)構(gòu)-----堆的基本操作和應(yīng)用

發(fā)布時(shí)間:2020-07-18 09:23:11 來源:網(wǎng)絡(luò) 閱讀:363 作者:馬尾和披肩 欄目:編程語言

                       (一)用仿函數(shù)實(shí)現(xiàn)大堆小堆

堆數(shù)據(jù)結(jié)構(gòu)是一種數(shù)組對象,它可以被視為一棵完全二叉樹結(jié)構(gòu)。

堆結(jié)構(gòu)的二叉樹存儲是

最大堆:每個(gè)父節(jié)點(diǎn)的都大于孩子節(jié)點(diǎn)。

最小堆:每個(gè)父節(jié)點(diǎn)的都小于孩子節(jié)點(diǎn)。


仿函數(shù)(functor),就是使一個(gè)類的使用看上去象一個(gè)函數(shù)。其實(shí)現(xiàn)就是類中實(shí)現(xiàn)一個(gè)operator(),這個(gè)類就有了類似函數(shù)的行為,就是一個(gè)仿函數(shù)類了。
在實(shí)現(xiàn)大,小堆的過程中,有些功能的的代碼,會在不同的成員函數(shù)中用到,想復(fù)用這些代碼,有兩種途徑。

 1)公共的函數(shù),這是一個(gè)解決方法,不過函數(shù)用到的一些變量,就可能成為公共的全局變量,再說為了復(fù)用這么一片代碼,就要單立出一個(gè)函數(shù),也不是很好維護(hù)。

 2)仿函數(shù),寫一個(gè)簡單類,除了那些維護(hù)一個(gè)類的成員函數(shù)外,就只是實(shí)現(xiàn)一個(gè)operator(),在類實(shí)例化時(shí),就將要用的,非參數(shù)的元素傳入類中。

在C++里,我們通過在一個(gè)類中重載括號運(yùn)算符的方法使用一個(gè)函數(shù)對象而不是一個(gè)普通函數(shù)

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;   
}

用仿函數(shù)實(shí)現(xiàn)大堆,小堆的基本結(jié)構(gòu)

#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>>//默認(rèn)建大堆
class Heap
{
private:
	vector<T> _a;
public:

	Heap(const T* a,size_t size)
	{
		assert(a);
		//將數(shù)組中的數(shù)據(jù)壓入棧中
		for(i=0;i<size;i++)
		{
		_a.push_back(a[i]);
		}
		//建大堆
		for(int i=(_a.size()-2)/2;i>=0;i--)
		{
		//向下調(diào)整
		_AdjustDown(i);
		}
	}
	//向堆中插入數(shù)據(jù)
	void push(const T& x)
	{
	_a.push_back (x);
	_Adjustup(_a.size()-1)
	}
/********************
在彈出的時(shí)候使用的方法是
先將完全二叉樹的根節(jié)點(diǎn)與最后一個(gè)葉子節(jié)點(diǎn)交換,
彈出當(dāng)前的葉子節(jié)點(diǎn),然后在向下調(diào)整
************************/
	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;
			//找出兩個(gè)孩子中最大的一個(gè)
			if(com(_a[child+1],_a[child]) && child+1<_a.size())//因?yàn)槭峭耆鏄渌杂液⒆涌赡懿淮嬖?			{
			child=child+1;
			}
			//如果孩子大于父親則交換繼續(xù)往下調(diào)整
			if(com(_a[child],_a[parent]))
			{
			swap(_a[child],_a[parent]);
			parent=child;
			child=2*parent+1;
			}
			//否則滿足大根堆,退出循環(huán)
			else
			{
			break;
			}
		}
	
	}

	//向上調(diào)整
	void _Adjustup(size_t child)
	{
		 size_t parent=(child-1)/2;
		 while(child>0)//不能寫成while(parent>0),因?yàn)閏hild為size_t 類型,會構(gòu)成死循環(huán)
		 {
			 Comper com;
			 //如果插入的子節(jié)點(diǎn)大于根節(jié)點(diǎn),則交換
			 if(com(_a[child],_a[parent]))
			 {
			 swap(_a[child],_a[parent]);
			 child=parent;
			 parent=(child-1)/2;
			 }
			 //否則滿足大堆,退出循環(huán)
			 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);
	}
	//選出一個(gè)數(shù)據(jù)交換到末尾,利用帥選法將前N-i個(gè)元素重新帥選建成一個(gè)堆
	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;

}



向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI