堆数据结构的模板类_类的创建需要注意的地方

完成一个之前堆数据结构的模板类,关于类的创建需要注意的:

  1. 默认构造函数,没有声明编译器会自动创建,创建类的时候调用默认构造函数。默认构造函数可以使带默认参数的。
  2. 析构函数,没有声明编译器会自动创建,对动态分配来说会造成内存泄漏等问题
  3. 复制构造函数,类作为函数参数(按值传递)的时候会新建临时副本,就需要调用复制构造函数,之后还会调用析构函数,就会产生问题,复制构造会单纯复制非静态成员(也就是动态分配的指针,而不是带内容的指针)。所以应该自己定义复制构造函数完成内存申请等操作。同时应该函数用引用传递类对象,节约调用构造函数与空间
  4. 赋值运算符(=)重载一下赋值运算符,否则无法进行类赋值,用重载的函数完成数据成员的内存申请,赋值等,然后返回一个当前对象的引用即可

这个堆的类:类内一个struct数组,一个模板data,动态分配内存。一个struct里面存1权值,用来排序,2索引,用来找模板data,因为考虑到可能数据比较复杂的话,移动数据的开销比较大了,而改变一个位置里面存的索引是比较简单。同时后来加了一个valid的数据,用来记录哪些位置的data是有效的,因为后面增加了删除元素的操作,如果把后面元素前移的话就比较麻烦了,每个位置的索引都要移动,所以就加了这个valid。

#include <iostream>
#include <string.h>
using namespace std;
struct heap_struct
{
	int value;//用来排序的键值,可能叫key好点
	int index;//存相应数据的索引
};

template <class Type>
class heap_class
{
	private:
		heap_struct *p_struct;
		Type *data;//数据的指针
		unsigned char *data_valid;//记录哪些位置的数据是有效的 
		int len;//元素个数 
		int size;//	有效对数目 ,是在最大化堆中的一个中间变量heap_size 
		int max_len;//这个定义成分配的数组大小,类似vector的处理方法,避免频繁的内存操作 
	public:
		heap_class();
		heap_class(heap_class<Type> & arg);
		~heap_class();
		int Parent(int i);
		int Left(int i);
		int Right(int i);
		void Swap(int & a,int & b);
		void Swap(heap_struct & a,heap_struct & b);
		void MaxHeap(int i);
		void BuildMaxHeap(); 
		//插入元素与相应键值
		void Insert(const Type & x,const int &value); 
		void ShowAll();
		Type MaxEle();//返回最大键值的元素,但不从类内删除 
		Type DelMaxEle();//删除最大键值的元素,并返回 
		bool IncreaseKey(const Type x,const int k);//把元素x的键值增加到k,就需要从元素反找键值了,可惜数据里面没存键值的信息,没办法很快反找到。只能遍历找了 
};

template <class Type>//默认构造函数 
heap_class<Type>::heap_class()
{
	len = 0;
	size = 0;
	max_len = 1024;//默认大小1024 
	p_struct = new heap_struct[max_len];
	data = new Type[max_len];
	data_valid = new unsigned char[max_len];
	memset(data_valid,0,sizeof(unsigned char)*max_len);
	cout<<"default"<<endl;
}

template <class Type>//构造函数 
heap_class<Type>::heap_class(heap_class<Type> & arg)
{
	len = arg.len;
	size = arg.size;
	max_len = arg.max_len;
	delete [] p_struct;
	p_struct = new heap_class[max_len];
	delete [] data;
	data = new Type[max_len];
	data_valid = new unsigned char[max_len];
	memcpy(p_struct,arg.p_struct,sizeof(heap_struct)*len);
	memcpy(data,arg.data,sizeof(Type)*len);
	memcpy(data_valid,arg.data_valid,sizeof(unsigned char)*len);
}

template <class Type>//默认析构函数 
heap_class<Type>::~heap_class()
{
	len = 0;
	size = 0;
	delete [] p_struct;
	delete [] data;
	delete [] data_valid;
}

template <class Type>
inline int heap_class<Type>::Parent(int i)//返回父节点的坐标索引,数组都是索引从0开始,
{
	return  (i+1)/2-1;
}

template <class Type>
inline int heap_class<Type>::Left(int i)//返回左子节点的坐标索引,数组都是索引从0开始,
{
	return 2*(i+1)-1;
}

template <class Type>
inline int heap_class<Type>::Right(int i)//返回右子节点的坐标索引,数组都是索引从0开始,
{
	return 2*(i+1);
}

template <class Type>
inline void heap_class<Type>::Swap(int & a,int & b)
{
	int tmp;
	tmp = a;
	a = b;
	b = tmp;
	return;
}

template <class Type>
inline void heap_class<Type>::Swap(heap_struct & a,heap_struct & b)
{
	heap_struct tmp;
	tmp = a;
	a = b;
	b = tmp;
	return;
}

template <class Type>
void heap_class<Type>::MaxHeap(int i)//i是索引,对键值结构的处理,不涉及到数据 
{
	int l = Left(i);//9
	int r = Right(i);//10
	int largest = i;//4
	if(l<size && p_struct[l].value>p_struct[i].value)//这里size是数目,第一次是n,而l,r是索引,所以比较的 边界是size-1 
		largest = l;
	if(r<size && p_struct[r].value>p_struct[largest].value)
		largest = r;
	cout<<"heap i="<<i<<"size="<<size<<"largest="<<largest<<endl;
	if(largest!=i)
	{
		Swap(p_struct[i],p_struct[largest]);
		MaxHeap(largest);
	}
	return;
} 

template <class Type>
void heap_class<Type>::BuildMaxHeap()//对键值结构的处理,不涉及到数据 
{
	size = len;//这步假设全都没排序,然后用于调用MaxHeap
	for(int i=len/2-1;i>=0;i--)
		MaxHeap(i); 
	cout<<"after build"<<endl;
	for(int i=0;i<len;i++)
		cout<<"i="<<i<<" value[i]="<<p_struct[i].value<<" index="<<p_struct[i].index<<endl;
}

template <class Type>
void heap_class<Type>::Insert(const Type &x,const int &value)
{
	len +=1;
	size +=1;
	
	heap_struct s;
	//s.index = len-1;一开始没valid的index处理 
	for(int i=0;i<len;i++)
	{
		if(data_valid[i] == 0)
		{
			s.index = i;
			data_valid[i] = 1; //这个位置用过  
			break;
		}
	} 
	s.value = value;
	if(max_len<len)//看看加入新元素以后 有没有超过原来max_len,超过了就开辟空间再复制元素过去 
	{
		max_len += 1024;
		heap_struct *tmp_struct = new heap_struct[max_len];
		if(p_struct!=NULL) 
		{
			cout<<"memcpy"<<endl;
			cout<<"memcpy len="<<sizeof(heap_struct)*(len-1)<<endl;
			memcpy(tmp_struct,p_struct,sizeof(heap_struct)*(len-1));//这里len加了一,所以把原来的数据复制过来的时候长度减个1 
		}
		tmp_struct[len-1] = s;
		if(p_struct!=NULL)
		{
			cout<<"delete"<<endl;
			delete [] p_struct;
		} 
		p_struct = tmp_struct;
		
		Type *tmp_data = new Type[max_len];
		if(data!=NULL) memcpy(tmp_data,data,sizeof(Type)*(len-1));
		tmp_data[s.index] = x;
		if(data!=NULL) delete [] data;
		data = tmp_data;
	}
	else//没超过的话,直接加入新元素 
	{
		p_struct[len-1] = s; 
		data[s.index] = x;
	}
 
	

	cout<<"cpy finished"<<endl;
	cout<<"size="<<size<<"len="<<len<<endl;
	BuildMaxHeap(); 
	
	return;
	 
}

template <class Type>
void heap_class<Type>::ShowAll()
{
	for(int i=0;i<len;i++)
	{
		cout<<"value="<<p_struct[i].value<<endl;

	}
	for(int i=0;i<len;i++)
	{

		cout<<"index="<<p_struct[i].index<<endl;

	}	
	for(int i=0;i<len;i++)
	{
		cout<<"data="<<data[i]<<endl;
	}	
	
}

template <class Type>
Type heap_class<Type>::MaxEle()
{
	int index_tmp;
	index_tmp = p_struct[0].index;
	return data[index_tmp]; 
}

template <class Type>
Type heap_class<Type>::DelMaxEle()//感觉可以不考虑效率的话,直接删掉元素然后调用build即可,但会对除了顶层根节点以外的其他根节点进行一次判断,但是单纯只是判断,还可以接受 
{
	if(len<0)
	{
		Type tmp;
		cout<<"no element"<<endl;
		return tmp;
	}
	heap_struct tmp = p_struct[0];//最大键值 
	Type max_element = data[tmp.index];//最大键值对应的元素
	data_valid[tmp.index] = 0;//这个位置又空了下来 
	
	p_struct[0] = p_struct[len-1];//最后一个位置的键值拿过来

	
	size = size-1;//这一步可有可无,因为排序的时候先假设了size=len 
	len = len-1;
	MaxHeap(0);
	//这里也可以调 BuildMaxHeap(); 里面会从其他根节点判断一次,一直判断到顶层根节点才会出现不符合的情况,再调用这个Maxheap方法,
	return max_element; 
	
	
} 

template <class Type>
bool heap_class<Type>::IncreaseKey(const Type x,const int k)
{
	int index,flag=0;
	for(index=0;index<len;index++)
	{
		if(data[index]==x)
		{
			flag=1;
			break;
		}
	}
	if(flag==0)
	{
		cout<<"can't find "<<x<<endl;
		return false;
	} 
	for(int i=0;i<len;i++)
	{
		if(p_struct[i].index==index)
		{
			p_struct[i].value = k;
			return true;
		}
	}
	
} 

int main()
{
	class heap_class<char> test;
	char c[11] = "abcdefghij";
	test.Insert(c[0],16);
	test.Insert(c[1],14);
	test.Insert(c[2],10);
	test.Insert(c[3],4);
	test.Insert(c[4],7);
	test.Insert(c[5],9);
	test.Insert(c[6],3);
	test.Insert(c[7],2);
	test.Insert(c[8],8);
	test.Insert(c[9],1);
	test.ShowAll();
	char c_max = test.DelMaxEle();
	cout<<"c_max="<<c_max<<endl;
	test.ShowAll();
	test.Insert('A',15);
	test.ShowAll();
	test.IncreaseKey('A',18);
	test.ShowAll();
	return 0;
	
}

半个月过去再回头看写出来的时候发现有很多改进的地方,以后有空再看

 

猜你喜欢

转载自blog.csdn.net/zhangzhi2ma/article/details/82585894