• 哈夫曼树及堆


    哈夫曼树及堆

    一、哈夫曼树

    最优二叉树,是一类带权路径长度最短的树

    所谓树的带权路径长度,就是树中所有叶节点的权值乘上其到根节点的路径长度(若根节点为0层,叶节点到根节点的路径长度为叶节点的层数)。树的路径长度是从树根到每一节点的路径长度之和

    权值自己设定

    二、堆

    最大(小)堆,其实就是最大(小)完全二叉树

    三、最大堆

    特性

    1.是完全二叉树,满足完全二叉树的特性

    2.堆中的任意一个节点的值都必须大于或等于其中最大的子节点的值

    四、最大堆的实现

    #pragma once
    template<typename T>
    class cmyheap
    {
    	T* pbuff;
    	size_t len;
    	size_t maxsize;
    public:
    	cmyheap();
    	~cmyheap();
    	void clear();
    	void appendnode(T const& scrdata);//从尾部追加数据
    	void deletenode();
    	void initheap(T arr[], size_t srclen);
    public:
    	void printfheap()
    	{
    		for (size_t i = 0; i < len; i++)
    		{
    			printf("%d	", pbuff[i]);
    		}
    		printf("
    ");
    	}
    };
    
    template<typename T>
     cmyheap<T>::cmyheap()
    {
    	 pbuff = nullptr;
    	 len = maxsize = 0;
    }
    
    template<typename T>
    cmyheap<T>::~cmyheap()
    {
    	clear();
    }
    
    template<typename T>
    void cmyheap<T>::clear()
    {
    	if (pbuff)
    		delete[]pbuff;
    	pbuff = nullptr;
    	len = maxsize = 0;
    }
    
    template<typename T>
    void cmyheap<T>::appendnode(T const & scrdata)
    {
    	if (len >= maxsize)
    	{
    		maxsize = maxsize + ((maxsize >> 1) > 1 ? (maxsize >> 1) : 1);
    		T* ptemp = new T[maxsize];
    		memcpy(ptemp, pbuff, sizeof(T)*len);
    		if (pbuff)
    		{
    			delete[]pbuff;
    			pbuff = nullptr;
    		}
    		pbuff = ptemp;
    	}
    	pbuff[len++] = scrdata;
    	//这只是实现了一颗完全二叉树,但并不是最大堆
    	//需要通过最后添加的这个节点的位置,去找父节点
    	//进行插入排序这种方式的比较和交换
    	//插入排序:将待排序数,和已排好序的数据进行比较,看用升序还是降序排序
    	//就是说要用最后一个添加的节点,依次与他的父节点相比进行交换,一直比到根节点为止(纵向次序--就是从下到上)
    
    
    	int tempindex = len - 1;//当前节点下标的位置
    	T tempnum = scrdata;//保存最后要添加的那个数据
    	//循环判断,最好的可能性,和父节点比较发现比父节点小,不交换。最坏的可能性,一直比到根节点
    	while (tempindex)//当这个值为0的时候,表示判断到了根节点
    	{
    		int parentindex = (tempindex - 1) >> 1;//得到父节点的下标
    		if (tempnum > pbuff[parentindex])
    		{
    			pbuff[tempindex] = pbuff[parentindex];//将父节点的数据赋值给当前节点,就是数据从上往下赋值
    		}
    		else
    			break;
    		tempindex = parentindex;//把父节点的下标赋值成当前节点下标
    	}
    	//上面执行的都是赋值操作,还没有操作要添加的数据
    	//要添加的数据,是拷贝给最后一个比较完的当前节点
    	pbuff[tempindex] = tempnum;//记得最后要添加的数据拷贝回去
    }
    
    //删除规则
    //1.每次只能删除根节点
    //2.把最后一个节点移动到根节点
    //3.调整根节点的位置,让这个二叉树重新满足堆的特性
    
    template<typename T>
     void cmyheap<T>::deletenode()
    {
    	 if (len == 0)
    		 return;
    	 //数组元素只能覆盖掉,不能删除
    	 if(len>1)//如果堆中只有一个根节点,不需要把最后一个节点的值再赋值给根节点
    		 pbuff[0] = pbuff[len - 1];
    	 len--;
    
    	 //下面要开始往下面进行比较了
    	 int index = 0;
    	 T tempnum = pbuff[0];//保存当前节点的值
    	 while (true)
    	 {
    		 int left = 2 * index + 1;//这是左子树的下标
    		 int right = 2 * index + 2;//这是右子树的下标
    		 //如果左子树的下标比最后的节点的下标还要大,就直接退出
    		 if (left > (int)len - 1)
    			 break;
    		 //到了这一步,证明当前节点下面至少有一个节点
    		 bool isleft = true;//假设和左子树比
    		 if (right<=(int)len-1)//证明右子树存在
    		 {
    			 if (pbuff[left] < pbuff[right])//且右边和左边大,那么就和右子树比较
    				 isleft = false;
    		 }
    		 //到了这里,找到左右子树中最大的那个节点了
    		 if (isleft)
    		 {
    			 //和左子树比较
    			 if (tempnum < pbuff[left])//证明当前节点比左子树小
    			 {
    				 pbuff[index] = pbuff[left];//将左子树赋值给当前节点
    				 index = left;//因为要一直比到条件不成立,所以要更新当前节点的下标
    			 }
    			 else//当前节点比左子树大,就不用交换了
    				 break;
    		 }
    		 else
    		 {
    			 //和右子树比较
    			 if (tempnum < pbuff[right])//证明当前节点比右子树小
    			 {
    				 pbuff[index] = pbuff[right];//将右子树赋值给当前节点
    				 index = right;//因为要一直比到条件不成立,所以要更新当前节点的下标
    			 }
    			 else//当前节点比右子树大,就不用交换了
    				 break;
    		 }
    	 }
    	 pbuff[index] = tempnum;//将当前节点的值赋值过去
    }
    
    
    //堆的删除
     //1.清空原来可能有的数据
     //2.一次在堆中加入所有元素
     //3.从最后一个有子节点的节点开始,依次调整次序满足最大堆的特性
    
     template<typename T>
    void cmyheap<T>::initheap(T arr[], size_t srclen)
     {
    	clear();//先清除原来树中可能存在的数据
    	if (srclen == 0)
    		return;
    	maxsize = srclen;
    	len = srclen;
    	pbuff = new T[maxsize];
    	for (size_t i = 0; i < len; i++)
    	{
    		pbuff[i] = arr[i];//用数组给这个二叉树初始化
    	}
    	
    
    	//上面只是将数据插入进来了,还没有构成最大堆
    	//(len-2)>>1----表示最后那个节点的父节点
    	for (int i = (len - 2) >> 1; i >= 0; i--)
    	{
    		int index = i;//当前节点的下标
    		T tempnum = pbuff[i];//保存当前节点的值
    		while (true)
    		{
    			int left = 2 * index + 1;//这是左子树的下标
    			int right = 2 * index + 2;//这是右子树的下标
    			//如果左子树的下标比最后的节点的下标还要大,就直接退出
    			if (left > (int)len - 1)
    				break;
    			//到了这一步,证明当前节点下面至少有一个节点
    			bool isleft = true;//假设和左子树比
    			if (right <= (int)len - 1)//证明右子树存在
    			{
    				if (pbuff[left] < pbuff[right])//且右边和左边大,那么就和右子树比较
    					isleft = false;
    			}
    			//到了这里,找到左右子树中最大的那个节点了
    			if (isleft)
    			{
    				//和左子树比较
    				if (tempnum < pbuff[left])//证明当前节点比左子树小
    				{
    					pbuff[index] = pbuff[left];//将左子树赋值给当前节点
    					index = left;//因为要一直比到条件不成立,所以要更新当前节点的下标
    				}
    				else//当前节点比左子树大,就不用交换了
    					break;
    			}
    			else
    			{
    				//和右子树比较
    				if (tempnum < pbuff[right])//证明当前节点比右子树小
    				{
    					pbuff[index] = pbuff[right];//将右子树赋值给当前节点
    					index = right;//因为要一直比到条件不成立,所以要更新当前节点的下标
    				}
    				else//当前节点比右子树大,就不用交换了
    					break;
    			}
    		}
    		pbuff[index] = tempnum;//将当前节点的值赋值过去
    	}
     }
    
    
  • 相关阅读:
    每日一题计划
    acm新手刷题攻略之poj
    Swift几行代码设置UIcollectionView的section底色,圆角
    简单几行代码设置UIcollectionView底色、section背景底色、背景色、背景阴影、背景圆角,支持CollectionView内容左对齐、居中对齐、右对齐、右对齐且右开始排序,支持底色点击反馈
    iOS12 EachNavigationBar导航栏操作出现黑边解决办法
    EachNavigationBar 导航栏颜色与给定颜色不相同设定
    详解冒泡排序法
    递归的简单用法
    判断一个整数是否为素数(质数)
    tcp黏包与拆包
  • 原文地址:https://www.cnblogs.com/Kissfly123/p/14636076.html
Copyright © 2020-2023  润新知