www.gusucode.com > 《C++高级语言程序设计》PPT及全书例子源代码-源码程序 > 《C++高级语言程序设计》PPT及全书例子源代码-源码程序/code/C++例题程序/第5章/s5_6/smain5_6_0.cpp

    //Download by http://www.NewXing.com
//主文件
//文件名:s5_6_0\smain5_6_0.cpp
//类声明及实现文件,对类模板,类的声明和实现放在同一个文件中。

//编译预处理语句:如果未定义__SCLASS5_6_0_T_H__则定义它,
//直到遇到#endif结束。
#ifndef __SCLASS5_6_0_T_H__ 
#define __SCLASS5_6_0_T_H__ 

#include <iostream>  		//包含头文件。使用iostream库

using namespace std; 		//使用std名字空间

//定义链表的节点结构类
class SNode
{

public:
	SNode( int value );
	~SNode( ){ };
	
	//公有数据,方便后面取值。
	int m_value;		//节点值
	SNode *m_next;		//节点后继,指向下一个节点的指针
};

//定义链表的类模板
template <class Type>
class TList
{
public:
	TList( );						//构造函数
	~TList( );						//析构函数

	virtual bool Insert( Type value );		//在链表头部插入一个节点
	bool Delete( Type value );			//在链表中删除值为value的一个节点,
	bool Contain( Type value );			//判断链表中是否包含某节点
	void Print( );					//输出链表节点的值。
protected:
	SNode *m_head;					//设置为只有头指针的单向链表。
};

//定义集合类模板--集合与链表采用同样的组织方式,如图6.1所示。
//但是链表和集合概念上有区别:集合中不允许有重复的节点。 
template<class Type>
class TSet : public TList<double>
{
public:
	bool Insert( double value );	//在集合中重载插入方法,插入前先判断节点是否已经存在。
};

#endif   					//结束编译预处理 

//节点类构造函数
SNode::SNode( int value )
{
	m_value = value;				//节点值
	m_next = NULL;				//节点后继
}

//构造函数
template <class Type>
TList<Type>::TList( )
{
	m_head = NULL;			//链表头
}

//链表析构函数。在析构函数中需要delete所有还在链表中的节点。
template <class Type>
TList<Type>::~TList( )
{
	SNode *p = m_head;			//
	for (  ; p != NULL;  )		//直到节点不为空。
	{
		m_head = p->m_next;		//头节点指向下一个节点,作为新的头节点
		delete p;				//释放p所指向的节点
		p = m_head;			//p指向新的头节点
	}
}

//在链表头部插入
template <class Type>
bool TList<Type>::Insert( Type value )
{
	SNode  *pTemp = new SNode( value );		//构造一个新节点
	if ( pTemp == NULL )					//节点空间申请不成功,退出。
	{
		return false;
	}
	
	pTemp->m_next = m_head;			//新节点的m_next指针指向头节点原来所指的节点。
	m_head = pTemp;				//头节点改为新生成的节点。
	return true;
}

template <class Type>
bool TList<Type>::Delete( Type value )
{
	SNode *p1, *p2;		//申请两个节点指针,用于节点操作时。
	//要遍历整个链表以查找其中是否包含有节点值为value的节点。
	//但是一次遍历只能够删除一个值为value的节点。
	//如果在链表中有多个值相同的节点,需要分别删除。
	if ( m_head->m_value == value )		//如果头节点就是要找的节点,直接删除。
	{
		p1 = m_head->m_next;			//p1指向头节点的后继节点
		delete m_head;				//释放头节点
		m_head = p1;				//p1成为新的头节点,即原头节点的后继成为新的头节点。
		return true;					//返回真。
	}
	else							//要删除的节点非头节点。
	{
		for ( p1 = m_head, p2 = m_head->m_next; p2 != NULL;   )//遍历链表
		{
			if ( p2->m_value == value )		//如果找到,则释放该节点,并结束遍历
			{
				p1->m_next = p2->m_next;	//p1指向p2的下一个节点。
				delete p2;				//释放p2.
				p2 = NULL;			//让p2指向NULL,该步骤通常很有必要。
				return true;				//结束遍历。
			}
			else						//如果该节点不是要找的节点,则p1,p2向后遍历。
			{
				p1 = p1->m_next;		//p1指向其后继
				p2 = p2->m_next;		//p2指向其后继。
			}
		}
	}
	return false;						//没有找到需要的节点,返回假。
}

template <class Type>
bool TList<Type>::Contain( Type value )
{
	//遍历链表以查找其中是否包含有节点值为value的节点,有返回true,没有返回false。
	for ( SNode  *p = m_head; p != NULL; p = p->m_next )
	{
		if ( p->m_value == value )			//找到有该节点,则返回。
		{
			return true;
		}
	}
	return false;
}

//显示表中的节点数据
template <class Type>
void TList<Type>::Print( )
{
	cout << "节点的值依次为:";
	//遍历链表以读出每一个节点的值并在终端上显示。
	for ( SNode  *p = m_head; p != NULL; p = p->m_next )
	{
		cout << " " << p->m_value << "; ";        		//显示节点值
	}
	cout << endl;								//结束输出流。
}


//集合类的节点插入方法。
template <class Type>
bool TSet<Type>::Insert( double value )
{
	//集合中没有包含value值的节点,才可以作插入操作,否则直接返回假。插入失败也返回假。
	if ( !( TList<double>::Contain( value ) )&&( TList<double>::Insert( value ) ) )
	{
		return true;
	}
	return false;
}


//主测试程序
void main( )  
{
	TList<int> sIntList;
	sIntList.Insert( 12 );
	sIntList.Insert( 24 );		//在链表sIntList中,两次插入24。
	sIntList.Insert( 48 );
	sIntList.Insert( 96 );
	sIntList.Insert( 24 );		//在链表sIntList中,两次插入24。
	sIntList.Print( );

	sIntList.Delete( 24 );		//删除一次24
	sIntList.Print( );

	TSet<double> sIntSet;
	sIntSet.Insert( 12.0 );
	sIntSet.Insert( 24.0 );		//在集合sIntList中,两次插入24。
	sIntSet.Insert( 48.0 );
	sIntSet.Insert( 96.0 );
	sIntSet.Insert( 24.0 );		//在集合sIntList中,两次插入24。
	sIntSet.Print( );

	sIntSet.Delete( 24.0 );		//删除一次24
	sIntSet.Print( );

	cin.get( );
}