关于模板特化的一个问题

doran_zhu 2008-10-24 12:14:14
最近算法课要写个huffman编码的程序,而正好最进在学C++,因此就用C++试试。首先定义了一个优先队列(一个最小堆)。建Huffman树的时候,需要使用这个优先队列保存二叉树结点指针,这就产生了一个问题,容器间元素的比较将变成指针间的比较,与要求的语义不符(我们希望比较的是指针指向的内容),于是写了针对二叉树结点指针的特化版本,但不知哪出问题了,每次都是访问内存冲突,急盼高手相助。
最小堆的定义如下:
#include <iostream>
#include "BiTreeNode.h"

using std::cout;
using std::cerr;
using std::endl;

template<class T>
class Heap{
int heap_size;//current size of the heap
int heap_length;//total length of the heap
T* A;
public:
explicit Heap(int length)
:heap_size(0),heap_length(length)
{
A = new T[heap_length+1];//第0个数组单元不存数据
}

~Heap()
{
delete [] A;
}
private:
void HeapAdjust(T A[],int i,int n)
{
int j = 2*i;//j is i's left child
T tmp = A[i];
while(j <= n)
{
if(j < n && A[j] > A[j+1])
++j;
if(tmp <= A[j])
break;
A[j/2] = A[j];
j *= 2;
}
A[j/2] = tmp;
}
public:
bool top(T& data)
{
if(heap_size <= 0)
{
cerr<<"The heap is empty";
return false;
}
data = A[1];
return true;
}

bool pop(T& data)
{
if(heap_size <= 0)
{
cerr<<"heap underflow";
return false;
}
data = A[1];
A[1] = A[heap_size--];
HeapAdjust(A,1,heap_size);
return true;
}

bool Heap_Insert(T data)
{
int i = ++heap_size;
if(i > heap_length)
{
cerr<<"heap overflow";
--heap_size;
return false;
}
while(i > 1 && A[i/2] > data)
{
A[i] = A[i/2];
i /= 2;
}
A[i] = data;
return true;
}

bool Heap_empty()
{
if(heap_size <= 0)
return true;
return false;
}
};


template<>//对BiNode* 的特化
class Heap<BiNode* >
{
int heap_size;
int heap_length;
BiNode** A;
public:
explicit Heap(int length)
:heap_length(length),heap_size(0)
{
*A = new BiNode[heap_length+1];
}

~Heap()
{
delete [] *A;
}
private:
void HeapAdjust(BiNode** A,int i,int n)
{
int j = 2*i;
BiNode* tmp = A[i];
while(j <= n)
{
if(j < n && A[j]->freq > A[j+1]->freq)
++j;
if(tmp->freq <= A[j]->freq)
break;
*A[j/2] = *A[j];
j /= 2;
}
*A[j/2] = *tmp;
}
public:
bool top(BiNode* data)
{
if(heap_size <= 0)
{
cerr<<"The heap is empty";
return false;
}
*data = *A[1];
return true;
}

bool pop(BiNode* data)
{
if(heap_size <= 0)
{
cerr<<"heap underflow";
return false;
}
*data = *A[1];
*A[1] = *A[heap_size--];
HeapAdjust(A,1,heap_size);
return true;
}

bool Heap_Insert(BiNode* data)
{
int i = ++heap_size;
if(i > heap_length)
{
cerr<<"heap overflow";
--heap_size;
return false;
}
while(i > 1 && A[i/2]->freq > data->freq)
{
*A[i] = *A[i/2];
i /= 2;
}
*A[i] = *data;
return true;
}

bool Heap_empty()
{
if(heap_size <= 0)
return true;
return false;
}
};
二叉树结点的定义如下:
BiTreeNode.h
#include <iostream>
using std::ostream;

class BiNode
{
public:
char name;//字母的名字
int freq;//出现频率
BiNode* left;//left child
BiNode* right;//right child
BiNode* parent;//parent
public:
BiNode()
{
}

BiNode(char n,int f = 0)
:name(n),freq(f),
left(0),right(0),parent(0)
{
}

~BiNode()
{
}
public:
bool operator==(const BiNode& src)
{
return (this->name==src.name) &&
(this->freq==src.freq)&&
(this->left==src.left)&&
(this->right==src.right)&&
(this->parent==src.parent);
}

bool operator!=(const BiNode& src)
{
return !operator==(src);
}

BiNode& operator=(const BiNode& src)
{
if(*this != src)
{
this->name = src.name;
this->freq = src.freq;
this->left = src.left;
this->right = src.right;
this->parent = src.parent;
}
return *this;
}

friend bool operator<(const BiNode& lhs,const BiNode& rhs);
friend bool operator>(const BiNode& lhs,const BiNode& rhs);
friend bool operator<=(const BiNode& lhs,const BiNode& rhs);
friend bool operator>=(const BiNode& lhs,const BiNode& rhs);
friend ostream& operator<<(ostream& os,const BiNode& node);
friend BiNode& operator+(BiNode& lhs,BiNode& rhs);
};

bool operator>(const BiNode& lhs,const BiNode& rhs)
{
return lhs.freq > rhs.freq;
}

bool operator<(const BiNode& lhs,const BiNode& rhs)
{
return lhs.freq < rhs.freq;
}

bool operator>=(const BiNode& lhs,const BiNode& rhs)
{
return !(operator<(lhs,rhs));
}

bool operator<=(const BiNode& lhs,const BiNode& rhs)
{
return !(operator>(lhs,rhs));
}

ostream& operator<<(ostream& os,const BiNode& node)
{
return os<<node.name<<':'<<node.freq;
}

BiNode& operator+(BiNode& lhs,BiNode& rhs)
{
BiNode* bi = new BiNode;
bi->freq = lhs.freq+rhs.freq;
bi->left = &lhs;
bi->right = &rhs;
bi->parent = 0;

lhs.parent = bi;
rhs.parent = bi;
return *bi;
}
下面是一个测试程序:
int main()
{
Heap<BiNode* > heap(30);
heap.Heap_Insert(new BiNode('a',12));
heap.Heap_Insert(new BiNode('b',11));
heap.Heap_Insert(new BiNode('c',1));
heap.Heap_Insert(new BiNode('d',2));
heap.Heap_Insert(new BiNode('e',5));

BiNode* p = 0;
while(!heap.Heap_empty())
{
heap.pop(p);
cout<<*p<<endl;
}
}

程序执行时,显示访问冲突。盼高手解救!
...全文
137 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
baihacker 2008-10-24
  • 打赏
  • 举报
回复
#include <iostream> 
using std::ostream;

class BiNode
{
public:
char name;//字母的名字
int freq;//出现频率
BiNode* left;//left child
BiNode* right;//right child
BiNode* parent;//parent
public:
BiNode()
{
}

BiNode(char n,int f = 0)
:name(n),freq(f),
left(0),right(0),parent(0)
{
}

~BiNode()
{
}
public:
bool operator==(const BiNode& src)
{
return (this->name==src.name) &&
(this->freq==src.freq)&&
(this->left==src.left)&&
(this->right==src.right)&&
(this->parent==src.parent);
}

bool operator!=(const BiNode& src)
{
return !operator==(src);
}

BiNode& operator=(const BiNode& src)
{
if(*this != src)
{
this->name = src.name;
this->freq = src.freq;
this->left = src.left;
this->right = src.right;
this->parent = src.parent;
}
return *this;
}

friend bool operator <(const BiNode& lhs,const BiNode& rhs);
friend bool operator>(const BiNode& lhs,const BiNode& rhs);
friend bool operator <=(const BiNode& lhs,const BiNode& rhs);
friend bool operator>=(const BiNode& lhs,const BiNode& rhs);
friend ostream& operator <<(ostream& os,const BiNode& node);
friend BiNode& operator+(BiNode& lhs,BiNode& rhs);
};

bool operator>(const BiNode& lhs,const BiNode& rhs)
{
return lhs.freq > rhs.freq;
}

bool operator <(const BiNode& lhs,const BiNode& rhs)
{
return lhs.freq < rhs.freq;
}

bool operator>=(const BiNode& lhs,const BiNode& rhs)
{
return !(operator <(lhs,rhs));
}

bool operator <=(const BiNode& lhs,const BiNode& rhs)
{
return !(operator>(lhs,rhs));
}

ostream& operator <<(ostream& os,const BiNode& node)
{
return os <<node.name <<':' <<node.freq;
}

BiNode& operator+(BiNode& lhs,BiNode& rhs)
{
BiNode* bi = new BiNode;
bi->freq = lhs.freq+rhs.freq;
bi->left = &lhs;
bi->right = &rhs;
bi->parent = 0;

lhs.parent = bi;
rhs.parent = bi;
return *bi;
}
#include <iostream>

using std::cout;
using std::cerr;
using std::endl;

template <class T>
class Heap{
int heap_size;//current size of the heap
int heap_length;//total length of the heap
T* A;
public:
explicit Heap(int length)
:heap_size(0),heap_length(length)
{
A = new T[heap_length+1];//第0个数组单元不存数据
}

~Heap()
{
delete [] A;
}
private:
void HeapAdjust(T A[],int i,int n)
{
int j = 2*i;//j is i's left child
T tmp = A[i];
while(j <= n)
{
if(j < n && A[j] > A[j+1])
++j;
if(tmp <= A[j])
break;
A[j/2] = A[j];
j *= 2;
}
A[j/2] = tmp;
}
public:
bool top(T& data)
{
if(heap_size <= 0)
{
cerr <<"The heap is empty";
return false;
}
data = A[1];
return true;
}

bool pop(T& data)
{
if(heap_size <= 0)
{
cerr <<"heap underflow";
return false;
}
data = A[1];
A[1] = A[heap_size--];
HeapAdjust(A,1,heap_size);
return true;
}

bool Heap_Insert(T data)
{
int i = ++heap_size;
if(i > heap_length)
{
cerr <<"heap overflow";
--heap_size;
return false;
}
while(i > 1 && A[i/2] > data)
{
A[i] = A[i/2];
i /= 2;
}
A[i] = data;
return true;
}

bool Heap_empty()
{
if(heap_size <= 0)
return true;
return false;
}
};


template <>//对BiNode* 的特化
class Heap <BiNode* >
{
int heap_size;
int heap_length;
BiNode** A;
public:
explicit Heap(int length)
:heap_length(length),heap_size(0)
{
A = new BiNode*[heap_length+1];
}

~Heap()
{
delete [] *A;
}
private:
void HeapAdjust(BiNode** A,int i,int n)
{
int j = i*2;
BiNode* tmp = A[i];
while(j < n)
{
if(j+1 < n && A[j]->freq > A[j+1]->freq)
++j;
if(tmp->freq <= A[j]->freq)
break;
A[j/2] = A[j];
j *= 2;
}
A[j/2] = tmp;
}
public:
bool top(BiNode* data)
{
if(heap_size <= 0)
{
cerr <<"The heap is empty";
return false;
}
*data = *A[1];
return true;
}

bool pop(BiNode*& data)
{
if(heap_size <= 0)
{
cerr <<"heap underflow";
return false;
}
data = A[1];
A[1] = A[heap_size--];
HeapAdjust(A,1,heap_size);
return true;
}

bool Heap_Insert(BiNode* data)
{
int i = ++heap_size;
if(i > heap_length)
{
cerr <<"heap overflow";
--heap_size;
return false;
}
while(i > 1 && A[i/2]->freq > data->freq)
{
A[i] = A[i/2];
i /= 2;
}
A[i] = data;
return true;
}

bool Heap_empty()
{
if(heap_size <= 0)
return true;
return false;
}
};

int main()
{
Heap <BiNode* > heap(30);
heap.Heap_Insert(new BiNode('a',12));
heap.Heap_Insert(new BiNode('b',11));
heap.Heap_Insert(new BiNode('c',1));
heap.Heap_Insert(new BiNode('d',2));
heap.Heap_Insert(new BiNode('e',5));

BiNode* p = 0;
while(!heap.Heap_empty())
{
heap.pop(p);
cout <<*p <<endl;
}
}

d:\>a
c:1
d:2
e:5
b:11
a:12

d:\>

doran_zhu 2008-10-24
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 luansxx 的回复:]
引用 4 楼 doran_zhu 的回复:
我也试过重载BiNode*的比较运算符,但无法编译通过


是的,还有一个方法:就是重新定义Heap模板,加一个比较类模板参数

C/C++ codetemplate<classT, typename Less=std::less<T>>//小于号函数类型classHeap{intheap_size;//current size of the heapintheap_length;//total length of the heapT*A;
Less less;//< 函数对象...voidHeapAdjust(T A[],inti,intn)
{intj=2*i;//j is i…
[/Quote]
嗯,我按你说的方法改了程序,结果是对的,而且这样程序清晰、简洁多了!呵呵,多谢!获益匪浅
Fighting Horse 2008-10-24
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 doran_zhu 的回复:]
我也试过重载BiNode*的比较运算符,但无法编译通过
[/Quote]

是的,还有一个方法:就是重新定义Heap模板,加一个比较类模板参数


template <class T, typename Less = std::less<T> > // 小于号函数类型
class Heap{
int heap_size;//current size of the heap
int heap_length;//total length of the heap
T* A;
Less less; // < 函数对象
...
void HeapAdjust(T A[],int i,int n)
{
int j = 2*i;//j is i's left child
T tmp = A[i];
while(j <= n)
{
if(j < n && A[j] > A[j+1])
++j;
if(less(tmp, A[j]))
break;
A[j/2] = A[j];
j *= 2;
}
A[j/2] = tmp;
}
}

struct less_p
{
bool operator () (const BiNode *const & lhs,const BiNode *const & rhs)
{
return lhs->freq < rhs->freq;
}
};

int main()
{
Heap <BiNode*, less_p> heap(30);
...
}

wshcdr 2008-10-24
  • 打赏
  • 举报
回复
MK
doran_zhu 2008-10-24
  • 打赏
  • 举报
回复
多谢飞雪!我想再问一个问题,你修改的pop版本中,形式参数是BiNode*&,我将它改为BiNode*后,程序依然出错
,想为一下,这两种传参方式的区别,因为感觉引用的内部实现就是指针
doran_zhu 2008-10-24
  • 打赏
  • 举报
回复
我也试过重载BiNode*的比较运算符,但无法编译通过
Fighting Horse 2008-10-24
  • 打赏
  • 举报
回复
感觉你多此一举了,重载BiNode*的比较运算符不就行了
lily604 2008-10-24
  • 打赏
  • 举报
回复
顶 飞雪 太强了

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧