C++:双向链表

头文件CNode.h

#pragma once
template<class T>
class TLinkList;
template<class T>
class TOrderedLinkList;
class CNode
{

public:
	friend class TLinkList<int>;
	/*friend class TOrderedLinkList<int>;*/
	CNode(int value);
	~CNode();

	int m_value;
	CNode* m_pNext;
	CNode* m_pPre;
};
CNode::CNode(int value)
{
	m_value = value;
	m_pNext = NULL;
	m_pPre = NULL;
}
CNode::~CNode() {}
template<class T>
class TLinkList
{
public:
	TLinkList();
	~TLinkList();

	virtual bool Insert(T value);//在链表中插入一个值,头插
	bool Delete(T value);//删除结点值为value的结点
	bool Search(T value);//判断链表中是否有值为value的结点
	bool Modify(T v1, T v2);//查找结点为v1,修改为v2
	virtual void Print();
	CNode* m_pHead;
};
template<class T>
class TOrderedLinkList :public TLinkList<T>
{
public:
	CNode* m_pHead;
	TOrderedLinkList(); //构造函数
	virtual ~TOrderedLinkList(); //析构函数
	virtual bool Insert(T value); //有序插入
	virtual void Print(); //按照链表顺序输出链表中的节点值
};

源文件

        

#include<iostream>
#include "CNode.h"
using namespace std;
//提前声明两个链表类 否则使用友元时会报错



template<class T>
TLinkList<T>::TLinkList()
{
	m_pHead = NULL;
}
template<class T>
TLinkList<T>::~TLinkList()
{
	CNode* p = m_pHead;
	for (; p != NULL;)
	{
		m_pHead = p->m_pNext;//将头指针指向下一节点
		delete p;            //释放掉该p指针
		p = m_pHead;         //将新的结点设置为头指针
	}
}
template<class T>
bool TLinkList<T>::Insert(T value)
{
	CNode* pTemp = new CNode(value);//创建一个新的临时结点
	if (pTemp == NULL)//申请内存不成功 退出程序
		exit(0);
	if (m_pHead == NULL)//头指针为空
	{
		pTemp->m_pNext = NULL;
		pTemp->m_pPre = NULL;
		m_pHead = pTemp;
	}
	else
	{
		pTemp->m_pNext = m_pHead; // 1. 将原头节点设置为新头节点的后继
		pTemp->m_pPre = NULL; // 2. 将新头节点的前驱设置为NULL
		m_pHead->m_pPre = pTemp; // 3. 将新头节点设置为原头节点的前驱
		m_pHead = pTemp;	// 4. 将新头节点设置为新的表头。
	}
	return true;
}
template<class T>
bool TLinkList<T>::Delete(T value)
{
	bool flag = false;
	CNode oCN(0);//0表示没有删除任何结点,1表示删除了
	oCN.m_pNext = m_pHead;//在头指针前添加一个结点 方便结点的删除
	oCN.m_pPre = NULL;
	m_pHead->m_pPre = &oCN;
	m_pHead = &oCN;
	CNode* p1 = m_pHead, * p2 = m_pHead->m_pNext;
	for (; p2 != NULL;)
	{
		if (p2->m_value == value)//p2所指的结点正是要删除的结点
		{
			p1->m_pNext = p2->m_pNext;
			(p2->m_pNext)->m_pPre = p1;
			delete p2;
			p2 = p1->m_pNext;
			flag = true;
		}
		else
		{
			p1 = p2;
			p2 = p2->m_pNext;
		}
	}
	m_pHead = oCN.m_pNext;
	(oCN.m_pNext)->m_pPre = NULL;
	return flag;
}
template<class T>
bool TLinkList<T>::Search(T value)
{
	for (CNode* p = m_pHead; p != NULL; p++)
	{
		if (p->m_value == value)
		{
			return true;
		}
	}
	return false;
}
template<class T>
bool TLinkList<T>::Modify(T v1, T v2)
{
	bool flag = false;
	for (CNode* p = m_pHead; p != NULL; p++)
	{
		if (p->m_value == v1)
		{
			p->m_value = v2;
			flag = 1;
		}
	}
	return flag;

}
template<class T>
void TLinkList<T>::Print()
{
	cout << "从TLinkList表头开始结点的值依次为:\n";
	for (CNode* p = m_pHead; p != NULL; p = p->m_pNext)
	{
		cout << p->m_value << " ";
	}
	cout << endl;
}


template <class T>
TOrderedLinkList<T>::TOrderedLinkList()
{
	m_pHead = NULL;
}
//TOrderedLinkList类模板的构造函数
template <class T>
TOrderedLinkList<T>::~TOrderedLinkList()
{ }
template <class T>
bool TOrderedLinkList<T>::Insert(T value) 
{
	CNode* p1,
		* p2; //定义两个指针插入操作时使用
	CNode* pTemp = new CNode(value);//定义pTemp指向new的待插入节点
	if (pTemp == NULL) //内存空间申请不成功
	{exit(0);} //停止执行程序
	if (m_pHead == NULL) //表头为空时插入为第一个节点
	{
		pTemp->m_pNext = NULL; //1. 新节点的后继为NULL
		pTemp->m_pPre = NULL; //2. 新节点的前驱为NULL
		m_pHead = pTemp; //3. 头指针指向新节点
	}
else //当表头不为空时,首先要寻找插入位置,然后才能插入节点
{
	if (value < m_pHead->m_value) //在表的头节点前插入
	{
		pTemp->m_pNext = m_pHead; // 1. 将原头节点设置为新头节点的后继
		pTemp->m_pPre = NULL; // 2. 将新头节点的前驱设置为NULL
		m_pHead->m_pPre = pTemp; // 3. 将新头节点设置为原头节点的前驱
		m_pHead = pTemp; // 4. 将新头节点设置为新的表头。
	}
	else //不是在头节点前插入
	{ //让p2指向p1的前驱(主要考虑链表尾部的插入)
		for (p2 = m_pHead, p1 = m_pHead->m_pNext; p1 != NULL; p2 = p1, p1 = p1->m_pNext)
		{
			if (value < p1->m_value) // 在链表中间插入
			{
				(p1->m_pPre)->m_pNext = pTemp; // 1. p1的前驱的后继指向新节点
				pTemp->m_pPre = p1->m_pPre; // 2. 新节点的前驱指向p1的前驱
				pTemp->m_pNext = p1; // 3. 新节点的后继指向p1
				p1->m_pPre = pTemp; // 4. p1的前驱指向新节点
				break;
			}
		}
		if (p1 == NULL) // 在链表末尾插入
		{
			pTemp->m_pNext = NULL; // 1. 新节点的后继设置为NULL
			pTemp->m_pPre = p2; // 2. 新节点的前驱指向p2
			p2->m_pNext = pTemp; // 3. p2的后继指向新节点
		}
	}
	}
	return true;
}
template<class T>
void TOrderedLinkList<T>::Print()
{
	for (CNode* p = m_pHead; p != NULL; p = p->m_pNext)
	{
		cout << p->m_value << " ";
	}
	cout << endl;
}
int main()
{
	TLinkList<int> oILL;
	oILL.Insert(12);
	oILL.Insert(24);
	oILL.Insert(48);
	oILL.Insert(96);
	oILL.Insert(24);
	oILL.Insert(48);
	oILL.Insert(96);
	oILL.Insert(35);
	oILL.Print();
	oILL.Delete(24);
	oILL.Print();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值