线性表—双链表、循环链表

双链表

双链表:在单链表基础上,增加了前驱指针的链表称为双链表。

    //双链表中每个节点的定义
	template  //T代表数据元素类型
	struct DblNode
	{
		T data; //数据域,用来存放数据元素
		DblNode* prior; //前趋指针,指向前一个同类型(和本节点类型相同)的节点
		DblNode* next; //后继指针,指向下一个同类型(和本节点类型相同)的节点
	};

    //双链表的定义
    template 
	class DblLinkList
	{
	public:
		DblLinkList(); //构造函数
		~DblLinkList(); //析构函数

	public:
		bool ListInsert(int i, const T& e);  //在第i个位置插入指定元素e
		bool ListDelete(int i);              //删除第i个位置的元素


		bool GetElem(int i, T& e);           //获得第i个位置的元素值
		int  LocateElem(const T& e);         //按元素值查找其在双链表中第一次出现的位置

		void DispList();                     //输出双链表中的所有元素
		int  ListLength();                   //获取双链表的长度
		bool Empty();                        //判断双链表是否为空

		bool InsertPriorNode(DblNode* pcurr, DblNode* pnewnode)
		{
			//在节点pcurr之前插入新节点pnewnode,请自行添加代码......
          
			if(nullptr==pcurr || nullptr==pnewnode)
				return false;
			pnewnode->next=pcurr;	//(1)让新节点next指向pcurr
			pnewnode->prior=pcurr->prior;	//(2)让新节点的prior指向pcurr的prior
			pcurr->prior->next=pnewnode;	//(3)让pcurr的前一个节点的next指向新节点
			pcurr->prior=pnewnode;	//(4)改变pcurr的prior,使其指向新节点
			return true;
		}

		bool DeleteNode(DblNode* pdel)
		{
			//删除pdel所指向的节点,请自行添加相关代码
            if(!pdel)
				return false;
			pdel->prior->next=pdel->next;
			pdel->next->prior=pdel->prior;
			delete pdel;
		}


	private:
		DblNode* m_head; //头指针(指向链表第一个节点的指针,如果链表有头结点则指向头结点)
		int m_length;    //双链表当前长度(当前有几个元素),为编写程序更加方便和提高程序运行效率而引入,但不是必须引入
	};

    //通过构造函数对双链表进行初始化
	template 
	DblLinkList::DblLinkList()
	{
		m_head = new DblNode; //先创建一个头结点
		m_head->next = nullptr; //该值暂时为nullptr,因为还没有后继节点
		m_head->prior = nullptr; //该值一直为nullptr
		m_length = 0;  //头结点不计入双链表的长度		
	}

    //通过析构函数对双链表进行资源释放
	template 
	DblLinkList::~DblLinkList()
	{
		DblNode* pnode = m_head->next;
		DblNode* ptmp;
		while (pnode != nullptr) //该循环负责释放数据节点
		{
			ptmp = pnode;
			pnode = pnode->next;

			delete ptmp;
		}
		delete m_head;    //释放头结点
		m_head = nullptr; //非必须
		m_length = 0;     //非必须
	}

    
    //在第i个位置(位置编号从1开始)插入指定元素e
	template 
	bool DblLinkList::ListInsert(int i, const T& e)
	{
		//判断插入位置i是否合法,i的合法值应该是1到length+1之间
		if (i < 1 || i >(m_length + 1))
		{
			cout << "元素" << e << "插入的位置" << i << "不合法,合法的位置是1到" << m_length + 1 << "之间!" << endl;
			return false;
		}

		DblNode* p_curr = m_head;

		//整个for循环用于找到第i-1个节点
		for (int j = 0; j < (i - 1); ++j)//j从0开始,表示p_curr刚开始指向的是第0个节点(头结点)
		{
			p_curr = p_curr->next; //pcurr会找到当前要插入的位置,比如要在第2个位置插入,pcurr会指向第1个位置(节点)
		}

		DblNode* node = new DblNode;
		node->data = e;
		node->next = p_curr->next;//让新节点链上后续链表,因为pcurr->next指向后续的链表节点

		node->prior = p_curr;
		if (p_curr->next != nullptr)
			p_curr->next->prior = node;

		p_curr->next = node;//让当前位置链上新节点,因为node指向新节点

		cout << "成功在位置为" << i << "处插入元素" << e << "!" << endl;
		m_length++;	        //实际表长+1
		return true;
	}

    //输出双链表中的所有元素,时间复杂度为O(n)
	template
	void DblLinkList::DispList()
	{
		DblNode* p = m_head->next;
		while (p != nullptr) //这里采用while循环或者for循环书写都可以
		{
			cout << p->data << " ";  //每个数据之间以空格分隔
			p = p->next;
		}
		cout << endl; //换行
	}

    //删除第i个位置的元素
	template < typename T>
	bool DblLinkList::ListDelete(int i)
	{
		if (m_length < 1)
		{
			cout << "当前双链表为空,不能删除任何数据!" << endl;
			return false;
		}
		if (i < 1 || i > m_length)
		{
			cout << "删除的位置" << i << "不合法,合法的位置是1到" << m_length << "之间!" << endl;
			return false;
		}

		DblNode* p_curr = m_head;

		//整个for循环用于找到第i-1个节点
		for (int j = 0; j < (i - 1); ++j)//j从0开始,表示p_curr刚开始指向的是第0个节点(头结点)
		{
			p_curr = p_curr->next; //pcurr会找到当前要删除的位置所代表的节点的前一个节点的位置,比如要删除第2个位置的节点,pcurr会指向第1个位置(节点)
		}

		DblNode* p_willdel = p_curr->next; //p_willdel指向待删除的节点
		DblNode* p_willdelNext = p_willdel->next; //p_willdelNext指向待删除节点的下一个节点
		p_curr->next = p_willdel->next; //第i-1个节点的next指针指向第i+1个节点
		if (p_willdelNext != nullptr)
			p_willdelNext->prior = p_curr;//第i+1个节点的prior指针指向第i-1个节点

		cout << "成功删除位置为" << i << "的元素,该元素的值为" << p_willdel->data << "!" << endl;
		m_length--;       //实际表长-1
		delete p_willdel;
		return true;
	}

 循环单链表

传统的循环单链表,把链表的头指针修改为尾指针  不再使用m_head, 引入一个尾指针m_tail,那么m_tail->next指向头节点。线性表—双链表、循环链表_第1张图片

 线性表—双链表、循环链表_第2张图片

如果需要频繁的在链表头或者链表尾进行数据操作的话,可以考虑引入m_tail表尾指针。

引入尾指针的另外一个好处就是可以迅速的将两个单循环链表连接起来形成一个更大的单循环链表。

线性表—双链表、循环链表_第3张图片

p1_head = m_tail1->next;  //先把单循环链表1的头节点暂存起来
m_tail1->next = m_tail2->next->next; //让单循环链表1的尾节点指向单循环链表2的头节点之后的节点(第一个数据节点,也就是a11)。
p2_head = m_tail2->next; //再把单循环链表2的头节点暂存起来
m_tail2->next = p1head; //让单循环链表2的为节点的next域指向单循环链表1的头结点。
//其他代码略:包括重新设置单循环链表2的长度,让单循环链表2的头指针的next指向自己。
//而对于单循环链表2的头结点的释放,其实是在CirLinlist类的析构函数中进行的。

 


    //单循环链表中每个节点的定义
	template  //T代表数据元素的类型
	struct Node
	{
		T        data;  //数据域,存放数据元素
		Node* next;  //指针域,指向下一个同类型(和本节点类型相同)节点
	};


    //单循环链表的定义
	template 
	class CirLinkList
	{
	public:
		CirLinkList();      //构造函数,参数可以有默认值
		~CirLinkList();     //析构函数

	public:
		bool ListInsert(int i, const T& e);  //在第i个位置插入指定元素e
		bool ListDelete(int i);              //删除第i个位置的元素

		bool GetElem(int i, T& e);           //获得第i个位置的元素值
		int  LocateElem(const T& e);         //按元素值查找其在单循环链表中第一次出现的位置

		void DispList();                     //输出单循环链表中的所有元素
		int  ListLength();                   //获取单循环链表的长度
		bool Empty();                        //判断单循环链表是否为空		


	private:
		Node* m_head; //头指针(指向链表第一个节点的指针,如果链表有头结点则指向头结点)
		int m_length;    //单循环链表当前长度(当前有几个元素),为编写程序更加方便和提高程序运行效率而引入,但不是必须引入
	};


    //通过构造函数对单循环链表进行初始化
	template 
	CirLinkList::CirLinkList()
	{
		m_head = new Node; //先创建一个头结点
		//m_head->next = nullptr;
		m_head->next = m_head;
		m_length = 0;  //头结点不计入单循环链表的长度		
	}


    //在第i个位置(位置编号从1开始)插入指定元素e
	template 
	bool CirLinkList::ListInsert(int i, const T& e)
	{
		//判断插入位置i是否合法,i的合法值应该是1到length+1之间
		if (i < 1 || i >(m_length + 1))
		{
			cout << "元素" << e << "插入的位置" << i << "不合法,合法的位置是1到" << m_length + 1 << "之间!" << endl;
			return false;
		}

		Node* p_curr = m_head;

		//整个for循环用于找到第i-1个节点
		for (int j = 0; j < (i - 1); ++j)//j从0开始,表示p_curr刚开始指向的是第0个节点(头结点)
		{
			p_curr = p_curr->next; //pcurr会找到当前要插入的位置,比如要在第2个位置插入,pcurr会指向第1个位置(节点)
		}

		Node* node = new Node;
		node->data = e;
		node->next = p_curr->next;//让新节点链上后续链表,因为pcurr->next指向后续的链表节点
		p_curr->next = node;//让当前位置链上新节点,因为node指向新节点

		cout << "成功在位置为" << i << "处插入元素" << e << "!" << endl;
		m_length++;	        //实际表长+1
		return true;
	}

    //删除第i个位置的元素
	template < typename T>
	bool CirLinkList::ListDelete(int i)
	{
		if (m_length < 1)
		{
			cout << "当前单循环链表为空,不能删除任何数据!" << endl;
			return false;
		}
		if (i < 1 || i > m_length)
		{
			cout << "删除的位置" << i << "不合法,合法的位置是1到" << m_length << "之间!" << endl;
			return false;
		}

		Node* p_curr = m_head;

		//整个for循环用于找到第i-1个节点
		for (int j = 0; j < (i - 1); ++j)//j从0开始,表示p_curr刚开始指向的是第0个节点(头结点)
		{
			p_curr = p_curr->next; //pcurr会找到当前要删除的位置所代表的节点的前一个节点的位置,比如要删除第2个位置的节点,pcurr会指向第1个位置(节点)
		}

		Node* p_willdel = p_curr->next; //p_willdel指向待删除的节点
		p_curr->next = p_willdel->next; //第i-1个节点的next指针指向第i+1个节点
		cout << "成功删除位置为" << i << "的元素,该元素的值为" << p_willdel->data << "!" << endl;
		m_length--;       //实际表长-1
		delete p_willdel;
		return true;
	}


    //获得第i个位置的元素值
	template
	bool CirLinkList::GetElem(int i, T& e)
	{
		if (m_length < 1)
		{
			cout << "当前单循环链表为空,不能获取任何数据!" << endl;
			return false;
		}

		if (i < 1 || i > m_length)
		{
			cout << "获取元素的位置" << i << "不合法,合法的位置是1到" << m_length << "之间!" << endl;
			return false;
		}

		Node* p_curr = m_head;
		for (int j = 0; j < i; ++j)
		{
			p_curr = p_curr->next;
		}
		e = p_curr->data;
		cout << "成功获取位置为" << i << "的元素,该元素的值为" << e << "!" << endl;
		return true;
	}

    //按元素值查找其在单循环链表中第一次出现的位置
	template
	int CirLinkList::LocateElem(const T& e)
	{
		Node* p_curr = m_head;
		for (int i = 1; i <= m_length; ++i)
		{
			if (p_curr->next->data == e)
			{
				cout << "值为" << e << "的元素在单循环链表中第一次出现的位置为" << i << "!" << endl;
				return i;
			}
			p_curr = p_curr->next;
		}
		cout << "值为" << e << "的元素在单循环链表中没有找到!" << endl;
		return -1;  //返回-1表示查找失败
	}

    //输出单循环链表中的所有元素,时间复杂度为O(n)
	template
	void CirLinkList::DispList()
	{
		Node* p = m_head->next;
		while (p != m_head) //这里采用while循环或者for循环书写都可以
		{
			cout << p->data << " ";  //每个数据之间以空格分隔
			p = p->next;
		}
		cout << endl; //换行
	}

    //获取单循环链表的长度,时间复杂度为O(1)
	template
	int  CirLinkList::ListLength()
	{
		return m_length;
	}

	//判断单循环链表是否为空,时间复杂度为O(1)
	template
	bool CirLinkList::Empty()
	{
		if (m_head->next == m_head) //单循环链表为空
		{
			return true;
		}
		return false;
	}


	//通过析构函数对单循环链表进行资源释放
	template 
	CirLinkList::~CirLinkList()
	{
		Node* pnode = m_head->next;
		Node* ptmp;
		while (pnode != m_head) //该循环负责释放数据节点
		{
			ptmp = pnode;
			pnode = pnode->next;

			delete ptmp;
		}
		delete m_head;    //释放头结点
		m_head = nullptr; //非必须
		m_length = 0;     //非必须
	}

 双向循环链表

线性表—双链表、循环链表_第4张图片

线性表—双链表、循环链表_第5张图片 

 

    //双循环链表中每个节点的定义
	template  //T代表数据元素的类型
	struct DblNode
	{
		T        data;  //数据域,存放数据元素
		DblNode* prior; //前趋指针,指向前一个同类型(和本节点类型相同)节点
		DblNode* next;  //后继指针,指向下一个同类型(和本节点类型相同)节点
	};

    //双循环链表的定义
	template 
	class DblCirLinkList
	{
	public:
		DblCirLinkList();      //构造函数,参数可以有默认值
		~DblCirLinkList();     //析构函数

	public:
		bool ListInsert(int i, const T& e);  //在第i个位置插入指定元素e
		bool ListDelete(int i);              //删除第i个位置的元素
				

		bool GetElem(int i, T& e);           //获得第i个位置的元素值
		int  LocateElem(const T& e);         //按元素值查找其在双循环链表中第一次出现的位置
		
		void DispList();                     //输出双循环链表中的所有元素
		int  ListLength();                   //获取双循环链表的长度
		bool Empty();                        //判断双循环链表是否为空

	private:
		DblNode* m_head; //头指针(指向链表第一个节点的指针,如果链表有头结点则指向头结点)
		int m_length;    //双循环链表当前长度(当前有几个元素),为编写程序更加方便和提高程序运行效率而引入,但不是必须引入
	};

    

    //通过构造函数对双循环链表进行初始化
	template 
	DblCirLinkList::DblCirLinkList()
	{		
		m_head = new DblNode; //先创建一个头结点
		m_head->next = m_head; 
		m_head->prior = m_head; 
		m_length = 0;  //头结点不计入双循环链表的长度		
	}

    //在第i个位置(位置编号从1开始)插入指定元素e
	template 
	bool DblCirLinkList::ListInsert(int i, const T& e)
	{
		//判断插入位置i是否合法,i的合法值应该是1到length+1之间
		if (i < 1 || i > (m_length + 1))
		{
			cout << "元素" << e << "插入的位置" << i << "不合法,合法的位置是1到" << m_length + 1 << "之间!" << endl;
			return false;
		}
		
		DblNode* p_curr = m_head;

		//整个for循环用于找到第i-1个节点
		for (int j = 0; j < (i-1); ++j)//j从0开始,表示p_curr刚开始指向的是第0个节点(头结点)
		{
			p_curr = p_curr->next; //pcurr会找到当前要插入的位置,比如要在第2个位置插入,pcurr会指向第1个位置(节点)
		}

		DblNode* node = new DblNode;
		node->data = e;	
		node->next = p_curr->next;//让新节点链上后续链表,因为pcurr->next指向后续的链表节点

		node->prior = p_curr;
		if(p_curr->next != nullptr)
			p_curr->next->prior = node; 

		p_curr->next = node;//让当前位置链上新节点,因为node指向新节点

		cout << "成功在位置为" << i << "处插入元素" << e << "!" << endl;
		m_length++;	        //实际表长+1
		return true;
	}

    //删除第i个位置的元素
	template < typename T>
	bool DblCirLinkList::ListDelete(int i)
	{
		if (m_length < 1)
		{
			cout << "当前双循环链表为空,不能删除任何数据!" << endl;
			return false;
		}
		if (i < 1 || i > m_length)
		{
			cout << "删除的位置" << i << "不合法,合法的位置是1到" << m_length << "之间!" << endl;
			return false;
		}

		DblNode* p_curr = m_head;

		//整个for循环用于找到第i-1个节点
		for (int j = 0; j < (i - 1); ++j)//j从0开始,表示p_curr刚开始指向的是第0个节点(头结点)
		{
			p_curr = p_curr->next; //pcurr会找到当前要删除的位置所代表的节点的前一个节点的位置,比如要删除第2个位置的节点,pcurr会指向第1个位置(节点)
		}

		DblNode* p_willdel = p_curr->next; //p_willdel指向待删除的节点
		DblNode* p_willdelNext = p_willdel->next; //p_willdelNext指向待删除节点的下一个节点
		p_curr->next = p_willdel->next; //第i-1个节点的next指针指向第i+1个节点
		if (p_willdelNext != nullptr)
			p_willdelNext->prior = p_curr;//第i+1个节点的prior指针指向第i-1个节点
		
		cout << "成功删除位置为" << i << "的元素,该元素的值为" << p_willdel->data << "!" << endl;
		m_length--;       //实际表长-1
		delete p_willdel;
		return true;
	}

    //获得第i个位置的元素值
	template
	bool DblCirLinkList::GetElem(int i, T& e)
	{
		if (m_length < 1)
		{
			cout << "当前双循环链表为空,不能获取任何数据!" << endl;
			return false;
		}

		if (i < 1 || i > m_length)
		{
			cout << "获取元素的位置" << i << "不合法,合法的位置是1到" << m_length << "之间!" << endl;
			return false;
		}

		DblNode* p_curr = m_head;
		for (int j = 0; j < i; ++j)
		{
			p_curr = p_curr->next; 
		}
		e = p_curr->data;
		cout << "成功获取位置为" << i << "的元素,该元素的值为" << e << "!" << endl;
		return true;
	}

	//按元素值查找其在双循环链表中第一次出现的位置
	template
	int DblCirLinkList::LocateElem(const T& e)
	{
		DblNode* p_curr = m_head;
		for (int i = 1; i <= m_length; ++i)
		{
			if (p_curr->next->data == e)
			{
				cout << "值为" << e << "的元素在双循环链表中第一次出现的位置为" << i<< "!" << endl;
				return i; 
			}
			p_curr = p_curr->next;
		}
		cout << "值为" << e << "的元素在双循环链表中没有找到!" << endl;
		return -1;  //返回-1表示查找失败
	}

	//输出双循环链表中的所有元素,时间复杂度为O(n)
	template
	void DblCirLinkList::DispList()
	{
		DblNode* p = m_head->next;
		while (p != m_head) //这里采用while循环或者for循环书写都可以
		{
			cout << p->data << " ";  //每个数据之间以空格分隔
			p = p->next;
		}
		cout << endl; //换行
	}

	//获取双循环链表的长度,时间复杂度为O(1)
	template
	int  DblCirLinkList::ListLength()
	{
		return m_length;
	}

	//判断双循环链表是否为空,时间复杂度为O(1)
	template
	bool DblCirLinkList::Empty()
	{
		if (m_head->next == m_head) //双循环链表为空
		{ 
			return true;
		}
		return false;
	}

	//通过析构函数对双循环链表进行资源释放
	template 
	DblCirLinkList::~DblCirLinkList()
	{		
		DblNode* pnode = m_head->next; 
		DblNode* ptmp;
		while (pnode != m_head) //该循环负责释放数据节点
		{
			ptmp = pnode;			
			pnode = pnode->next;

			delete ptmp;
		}
		delete m_head;    //释放头结点
		m_head = nullptr; //非必须
		m_length = 0;     //非必须
	}

你可能感兴趣的:(C++数据结构,c++,数据结构)