1.说明
现在开始注重编写一些公共的库,方便自己以后复用,为了提高复用性,采用了模板的方式,同时将这些库发布出来,供大家参考,如有问题或意见请发邮件zhang_int@sina.cn
2.最小堆
至于最小堆的思想,原理等再此就略过吧,结构很简单就不画UML了,简单说明下:
MinHeap.h:最小堆基类,对外部提供接口,方便以后扩展,如采用二叉树形式等
MinHeapArray.h:最小堆的具体实现,采用了数组的形式
Lock.h:线程锁的封装,封装库为ptherad,所以使用线程安全模式时,不支持跨平台
client.cpp:测试用例
现在就直接用代码说话
3.代码实现
//抽象的外部接口和基类 MinHeap.h
#ifndef __MINHEAP_H
#define __MINHEAP_H
#include <string>
#include <pthread.h>
#include "Lock.h"
/*
*@brief:外部对外抽象的接口,通过接口操作即可
*@author:zp
*/
template <class TYPE>
class CMinHeap
{
public:
CMinHeap(){}
virtual ~CMinHeap(){}
///@brief:添加元素,采用从上往下移动方式
virtual bool add(const TYPE p) = 0;
///@brief:获取小根堆头结点
///@ret:0 成功 -1 失败
virtual int front(TYPE& val) = 0;
///@brief:移除头结点元素
///@ret:0 成功 -1 失败
virtual int pop() = 0;
///@brief:返回堆中元素个数
virtual int size() = 0;
///@brief:获取最后状态错误信息
virtual const std::string& get_lasterror() = 0;
private:
};
#endif
//派生类,具体实现MinHeapArray.h
#ifndef __MINHEAPARRAY_H
#define __MINHEAPARRAY_H
#include "MinHeap.h"
/*************************************************************
@brief: 数组形式的最小堆,通过自动化测试,时间复杂度log(N)
@author:zp
@atention: 1.如果是自定义复合类型,需要重载 < > = 三个重载运算符,以确定比较方式
2.支持线程安全和非安全模式,所以编译时需链接 lpthread
//尚待测试点 函数指针,仿函数,模板函数传进来
//二叉树形式实现没有成功,以后再来把二叉树形式的写了吧
**************************************************************/
template <class TYPE>
class CMinHeapArray:public CMinHeap<TYPE>
{
public:
CMinHeapArray(const int size, const bool thrdsafe=false);
~CMinHeapArray();
///@brief:添加元素,采用从上往下移动方式
virtual bool add(const TYPE p);
///@brief:获取小根堆头结点
///@ret:0 成功 -1 失败
virtual int front(TYPE& val);
///@brief:移除头结点元素
///@ret:0 成功 -1 失败
virtual int pop();
///@brief:返回堆中元素个数
virtual int size();
///@brief:获取最后状态错误信息
virtual const std::string& get_lasterror();
private:
///小根堆元素保存的缓冲区
TYPE* m_heap;
///最小堆元素个数限制
int m_size;
///当前元素个数
int m_cur;
///最后状态错误原因
std::string m_lasterror;
///是否支持线程安全 true 支持 fales不支持
bool m_thrdsafe;
///线程安全锁
CLock m_lock;
};
template<class TYPE>
CMinHeapArray<TYPE>::CMinHeapArray(const int size, const bool thrdsafe)
{
if (size <= 0)
{
m_lasterror = "min-heap size illegal";
}
else
{
m_heap = new(std::nothrow) TYPE[size];
if (NULL == m_heap)
{
m_lasterror = "min-heap init error";
}
m_size = size;
m_cur = 0;
}
m_thrdsafe = thrdsafe;
}
template<class TYPE>
CMinHeapArray<TYPE>::~CMinHeapArray()
{
delete m_heap;
m_heap = NULL;
}
template <class TYPE>
inline const std::string& CMinHeapArray<TYPE>::get_lasterror()
{
if (m_thrdsafe)
m_lock.lock();
std::string& lasterror = m_lasterror;
if (m_thrdsafe)
m_lock.unlock();
return m_lasterror;
}
//bool add(const TYPE p, bool (*compare)(const TYPE a, const TYPE b)=NULL)
template <class TYPE>
bool CMinHeapArray<TYPE>::add(const TYPE p)
{
if (m_thrdsafe)
m_lock.lock();
int s;
s = m_cur;
int parent;
bool bflag = false;
if (m_cur < m_size)
{
while (s > 0)
{
parent = (s - 1) / 2;
if (m_heap[parent] < p)
break;
m_heap[s] = m_heap[parent];
s = parent;
}
m_heap[s] = p;
m_cur++;
bflag = true;
}
if (m_thrdsafe)
m_lock.unlock();
return bflag;
}
template <class TYPE>
int CMinHeapArray<TYPE>::front(TYPE& val)
{
if (m_thrdsafe)
m_lock.lock();
int flag = -1;
if (m_cur > 0)
{
flag = 0;
val = m_heap[0];
}
if (m_thrdsafe)
m_lock.unlock();
return flag;
}
///note:在弹出元素时,会将最后元素移动到被移走的空位处
template <class TYPE>
int CMinHeapArray<TYPE>::pop()
{
if (m_thrdsafe)
m_lock.lock();
int nret = -1;
int s = 0;
int half = 0;
int smallerpos = 0;
if (m_cur > 0)
{
nret = 0;
m_cur--;
half = m_cur / 2;
while (s < half)
{
int childl = s*2+1;
int childr = s*2+2;
smallerpos = childl;
if (childr < m_cur && m_heap[childl]>m_heap[childr])
smallerpos = childr;
if (m_heap[m_cur]<m_heap[smallerpos])
break;
m_heap[s] = m_heap[smallerpos];
s = smallerpos;
}
m_heap[s] = m_heap[m_cur];
}
if (m_thrdsafe)
m_lock.unlock();
return nret;
}
template<class TYPE>
inline int CMinHeapArray<TYPE>::size()
{
int size = 0;
if (m_thrdsafe)
m_lock.lock();
m_size = m_cur;
if (m_thrdsafe)
m_lock.unlock();
return m_cur;
}
#endif
//线程锁封装
#ifndef __LOCK_H
#define __LOCK_H
#include <pthread.h>
/***************************************************************
*@brief:linux平台线程锁
*@author:zp
*/
class CLock
{
public:
CLock()
{
_lock = new pthread_mutex_t;
pthread_mutex_init(_lock, NULL);
}
~CLock()
{
pthread_mutex_destroy(_lock);
delete _lock;
}
void lock()
{
pthread_mutex_lock(_lock);
}
void unlock()
{
pthread_mutex_unlock(_lock);
}
int trylock_mutex()
{
return pthread_mutex_trylock(_lock);
}
private:
pthread_mutex_t* _lock;
} ;
#endif
//测试用例
#include <iostream>
#include <stdlib.h>
#include <time.h>
/*
*@brief:最小堆测试和使用用例
*@attention:1.自定义复合结构需要重写 < > = 运算符 ,如有必要可以改成回调函数形式
* 2.在使用过程中如有逻辑问题或性能问题,请邮件zhang_int@sina.cn
*
*/
#include "MinHeap.h"
#include "MinHeapArray.h"
#define VAL_RANGE 20000
#define ARR_SIZE 9999
//自定义复合结构测试用例
typedef struct SMyStruct
{
std::string t1;
std::string t2;
int a;
int b;
bool operator < (SMyStruct val)
{
bool bret = false;
if (t1<val.t1)
bret = true;
return bret;
}
bool operator > (SMyStruct val)
{
bool bret = false;
if (t1>val.t1)
bret = true;
return bret;
}
bool operator = (SMyStruct val)
{
t1 = val.t1;
t2 = val.t2;
a = val.a;
b = val.b;
}
} TMyStruct;
bool judge(int front, int next)
{
bool bflag = true;
if (front > next)
{
bflag = false;
}
return bflag;
}
//批量自动化测试,随机构造数组大小,随机构造数组内的元素,然后放入到最小堆里面
//然后将数据弹出,查看是否是 升序
//保证最小堆能够可靠完整的运行
int batch_test()
{
//构建自动化测试,保证代码可靠运行
int arrsize;
while (1)
{
int* val;
arrsize = random() % ARR_SIZE;
if (arrsize == 0)
continue;
CMinHeap<int>* heap = new CMinHeapArray<int>(arrsize);
val = new int[arrsize];
for (int j=0; j<arrsize; j++)
{
int rand = random() % VAL_RANGE;
heap->add(rand);
val[j] = rand;
}
int size = heap->size();
int last;
int next;
bool bflag = true;
for (int i=0; i<size; i++)
{
if (i==0)
{
if (heap->front(last) == -1)
std::cout<<"front error last."<<std::endl;
}
else
{
if (heap->front(next) == -1)
std::cout<<"front error next."<<std::endl;
if (!judge(last, next))
{
bflag = false;
}
last = next;
}
//std::cout<<last<<" ";
heap->pop();
}
if (bflag == false)
{
std::cout<<"judge error."<<std::endl;
for (int i=0; i<arrsize; i++)
{
std::cout<<val[i]<<" ";
}
std::cout<<std::endl;
std::cin.get();
}
std::cout<<"test over "<<arrsize<< "!!!"<<std::endl;
usleep(1000);
delete heap;
heap = NULL;
delete val;
val = NULL;
}
return 0;
}
/*bool compare_min(TMyStruct a, TMyStruct b)
{
bool bret = false;
if (a.t1 < b.t1)
bret = true;
if (a.t1 == b.t1)
std::cout<<"equal."<<std::endl;
return bret;
}*/
void type_test(void)
{
TMyStruct b[10];
b[0].t1 = "nihao";
b[1].t1 = "test";
b[2].t1 = "1";
b[3].t1 = "god";
b[4].t1 = "msg";
b[5].t1 = "hehe";
b[6].t1 = "yumy";
b[7].t1 = "info";
b[8].t1 = "book";
b[9].t1 = "tea";
CMinHeap<TMyStruct>* heap = new CMinHeapArray<TMyStruct>(10, false);
for (int i=0; i<10; i++)
{
heap->add(b[i]);
}
int size = heap->size();
TMyStruct t;
for (int i=0; i<size; i++)
{
heap->front(t);
std::cout<<t.t1.c_str()<<" "<<std::endl;
heap->pop();
}
std::cin.get();
}
int main(void)
{
type_test();
batch_test();
return 0;
}