堆-链表实现

news/2024/5/20 10:13:05 标签: , 链表, 结构, 源码, heap

小顶大顶的概念大家应该都很熟悉了,如果不了解,可以搜索一下,网上很多介绍,而且很多源码实现,都很简单。

不过从网上看了一些的实现,都是用数组的。但是数组有一个缺陷,需要扩展时,就要复制原来的内存,申请新的空间。所以我在想能不能用链表,发现还真可以,就凑凑写了个代码。最后代码是写完了,发现其实链表没有必要,而且会占用更多的内存,尤其是对于那种int型变量,过多的指针真是浪费了大量内存。如果真要优化,可以针对数组做优化,链表不是出路。

反正代码写完了,拿出来晾一晾,呵呵。

代码在VS2008上编译测试通过,不过测试用例很简单。

#ifndef _HNWYLLMM_HEAP_H
#define _HNWYLLMM_HEAP_H

#include <map>
#include <iostream>
#include <cassert>

template<typename elem_t, typename cmp_func_t = std::less<elem_t> >
class cheap
{
public:
	cheap() : m_root(NULL), m_last(NULL), m_count(0)
	{

	}
	~cheap()
	{
		destroy() ;
	}

	int init()
	{
		m_last = m_root = NULL ;
		m_count = 0 ;
		return 0 ;
	}
	
	int	destroy()
	{
		cheap_node *node = m_root ;
		cheap_node *next = NULL ;
		while (node)
		{
			next = node->_next ;
			delete node ;
			node = next ;
		}
		m_root = m_last = NULL ;
		m_count ;
	}

	int size() const {return m_count ;}
	
	int	push(const elem_t &ele)
	{
		cheap_node *node = new cheap_node(ele) ;
		if (!node)
			return -1 ;
		
		m_count++ ;
		
		if (!m_last)
			m_root = m_last = node ;
		else
		{
			cheap_node *parent = m_last->_parent ;
			if (!parent)
			{
				parent = m_last ;
				m_last->_left = node ;
			}
			else if (parent->_left == m_last)
			{
				parent->_right = node ;
			}
			// parent's right child
			else if (parent->_next)
			{
				parent = parent->_next ;
				parent->_left = node ;
			}
			else
			{
				assert(0) ;
				parent = m_root ;
				for (parent = m_root ; parent->_left ; parent = parent->_left) ;
				
				parent->_left = node ;
			}
			m_last->_next = node ;
			
			node->_parent = parent ;
			node->_prev = m_last ;
			
			m_last = node ;			
		}
		
		// 调整
		cheap_node *next = m_last ;
		cheap_node *parent = NULL ;
		while ((parent = next->_parent) && 
				m_cmp_func(next->_data, parent->_data)
				)
		{
			elem_t tmp = next->_data ;
			next->_data = parent->_data ;
			parent->_data = tmp ;
		}
		
		return 0 ;
	}
	
	int	pop(elem_t &ele)
	{
		if (!m_root)
			return -1 ;
		
		ele = m_root->_data ;
		m_count-- ;
		
		if (m_last == m_root)
		{
			delete m_last ;
			m_root = m_last = NULL ;
			return 0 ;
		}
		
		m_root->_data = m_last->_data ;
		m_last->_data = NULL ;
		if (m_last->_parent)
		{
			if (m_last->_parent->_left == m_last)
			{
				m_last->_parent->_left = NULL ;
			}
			else
			{
				m_last->_parent->_right = NULL ;
			}
		}
		m_last = m_last->_prev ;
		delete m_last->_next ;
		m_last->_next = NULL ;
		
		for (cheap_node *last = m_root, *node = NULL ; last ;  last = node)
		{	
			if (last->_right)
			{
				if (m_cmp_func(last->_left->_data, last->_right->_data))
				{
					node = last->_left ;
				}
				else
					node = last->_right ;
			}
			else
				node = last->_left ;
			
			if (node)
			{
				if (m_cmp_func(node->_data, last->_data))
				{
					elem_t tmp = last->_data ;
					last->_data = node->_data ;
					node->_data = tmp ;
				}
				else
					break ;
			}
		}
		
		return 0 ;
	}

	friend cheap &operator <<(cheap &heap, const elem_t &ele)
	{
		heap.push(ele) ;
		return heap ;
	}

	friend cheap &operator >>(cheap &heap, elem_t &ele)
	{
		heap.pop(ele) ;
		return heap ;
	}

	void dump(std::ostream &os)
	{
		os << "dump: \n" ;
		int i = 1, lvl = 0 ;
		for (cheap_node *node = m_root ; node ; node = node->_next, i++)
		{
			os << node->_data << '\t' ;
			if (i == (1 << lvl) )
			{
				os << std::endl ;
				i = 0 ;
				lvl++ ;
			}
		}
		os << std::endl ;
	}
	
private:
	// 中的一个节点
	// 包含了树的结构链表结构
	// 还有一个数据
	class cheap_node
	{
	public:
		cheap_node *		_parent ;
		cheap_node *		_left ;
		cheap_node *		_right ;
		
		cheap_node *		_next ;
		cheap_node *		_prev ;
		
		elem_t 				_data ;
	public:
		cheap_node(const elem_t &ele) :
			_parent(NULL),
			_left(NULL),
			_right(NULL),
			_next(NULL),
			_prev(NULL),
			_data(ele)
		{
		}
		
		~cheap_node()
		{
		}
	};
	
private:
	cheap_node *	m_root ;		// 第一个数据
	cheap_node *	m_last ;		// 最后一个数据
	int				m_count ;		// 统计个数
	cmp_func_t		m_cmp_func ;	// 用来做比较的函数
};

#endif  // _HNWYLLMM_HEAP_H

测试文件:

main.cpp

#include <iostream>

#include "heap_array.h"

using namespace std ;

int main(void)
{
	cheap<int> heap ;
	heap.push(6) ;
	heap.dump(cout ) ;

//	heap.push(5) ;
//	heap << 100 << 5 << 9 << 11 ;
	heap << 100 ; heap.dump(cout) ;
	heap << 5 ; heap.dump(cout) ;
	heap << 9 ; heap.dump(cout) ;
	heap << 11 ; heap.dump(cout) ;

	heap.dump(cout) ;

	int num ;
	while (0 == heap.pop(num))
	{
		cout << num << endl ;
		heap.dump(cout) ;
	}
	return 0 ;
}


小顶大顶的概念大家应该都很熟悉了,如果不了解,可以搜索一下,网上很多介绍,而且很多源码实现,都很简单。 但是从网上看了一些的实现,都是用数组的。但是数组有一个缺陷,需要扩展时,就要复制原来的内存,申请新的空间。所以我在想能不能用链表,发现还真可以,就凑凑写了个代码。最后代码是写完了,发现其实链表没有必要,而且会占用更多的内存,尤其是对于那种int型变量,过多的指针真是浪费了大量内存。 反正代码写完了,拿出来晾一晾,呵呵。 代码在VS2008上编译测试通过,不过测试用例很简单。

http://www.niftyadmin.cn/n/734032.html

相关文章

LWN:使用GCC编译生成BPF程序

点击上方蓝色“Linux News搬运工”关注我们~Compiling to BPF with GCC By Jonathan Corbet LPC 自从在kernel里加上eBPF (extended BPF) 之后&#xff0c;诞生了很多各式各样的应用场景。不过还是只有很少人真正写过BPF代码。因为目前BPF代码就有点像其他那些汇编级语言&#…

HAProxy内存池简介

HAProxy介绍 HAProxy是一款提供高可用性、负载均衡以及基于TCP&#xff08;第四层&#xff09;和HTTP&#xff08;第七层&#xff09;应用的代理软件&#xff0c;HAProxy是完全免费的、借助HAProxy可以快速并且可靠的提供基于TCP和HTTP应用的代理解决方案。 HAProxy内存池概述…

LWN: 内核5.4版本合并窗口——第一部分

点击上方蓝色“Linux News搬运工”关注我们~5.4 Merge window, part 1By Jonathan Corbet截止2019年9月23日&#xff0c;已经有9632个patch set合入了5.4 kernel。本轮5.4版本的合并窗口的开局很不错。kernel代码中的修改遍布各处&#xff0c;包括不少清理工作以及bug fix。5.4…

Outlook VBA自动处理邮件

需求描述 公司里面每天都会有很多邮件&#xff0c;三分之一都是不需要看的&#xff0c;Outlook的过滤功能不错&#xff0c;都可以处理掉。还有些邮件&#xff0c;根据正文或者附件做一下处理自动转发出去就行了。于是上网搜集了一些资料&#xff0c;写个了小程序&#xff0c;共…

LWN:内核5.4版本合并窗口——第二部分

点击上方蓝色“Linux News搬运工”关注我们~5.4 Merge window, part 2By Jonathan Corbet译者按&#xff1a;本文有两个笑话&#xff0c;看得懂的才是真开发者。一个是"revert the revert of the revert patch"&#xff1b;另一个是supervisor -> hypervisor ->…

LWN: 修复getrandom()

点击上方蓝色“Linux News搬运工”关注我们~Fixing getrandom()By Jake Edge内核5.3版本里面有人报出一个启动过程中死机问题&#xff0c;最终演化成了一个影响很大的、充满争议性的linux-kernel mailing list讨论话题。大概介绍一下这里的问题&#xff0c;因为近期有些改动导致…

LWN: glibc里的系统调用封装函数

点击上方蓝色“Linux News搬运工”关注我们~System-call wrappers for glibcBy Jonathan CorbetLPCglibc&#xff0c;又名GNU C Library&#xff0c;过去长久以来大家对它的印象都是不愿意为Linux新加的系统调用增加wrapper&#xff08;封装函数&#xff09;。因此&#xff0c;…

HAProxy中描述符管理

在包含网络通讯的程序中&#xff0c;都需要管理描述符。描述符的管理也是服务器程序性能的关键点之一。很多开源软件&#xff0c;比如libevent和HAProxy都有自己的方式。但是他们都有相似的地方&#xff0c;并且目标都是一致的&#xff1a;把性能发挥到极致。因为当前的工作中也…