利用C++实现双向链表的基本操作

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43165699/article/details/97281946

利用C++实现双向链表的基本操作

本文采用利用C++实现了对双向链表的基本操作。操作包括:双向链表的构建、链表指定位置的插入、链表指定位置的删除、链表长度的获取、链表指定位置元素的获得及指定元素位置的获得、整体链表的删除。

双向链表是链表的另一种形式,它的结点特点是每个结点包括两个指针域和一个数据域,两个指针域Prior和Next分别指向该结点的前驱和后继元素。双向结点的结构如下图所示。
双向链表结点
双向链表除了头结点没有前驱和尾结点没有后继外,其他结点都有前驱结点和后驱结点,其结构下图所示。
双向链表结构
从图中的结构可以清楚的看到,双向链表可以从任何一个结点到达链表的头结点和尾结点。双向链表与单链表的操作过程类似,都可已进行插入、删除、获取、以及清空等基本操作。利用C++实现的具体代码如下。

#include<iostream>

using namespace std;

template<typename datatype> class doubleLink;       //双向链表声明
/***************************************双向链表数据结构定义*************************************************/
template<typename datatype>class doubleNode
{
public:

	//无参数构造函数,将指针域初始化为NULL
	doubleNode()
	{
		p_prior = NULL;
		p_next = NULL;
	}
   //带参数的构造函数,初始化数据域与指针域
	doubleNode(datatype item, doubleNode<datatype> * prior=NULL, doubleNode<datatype> * next=NULL)
	{
		data = item;
		p_prior = prior;
		p_next = next;
	}
	//析构函数
	~doubleNode()
	{
		p_prior = NULL;
		p_next = NULL;
	}

private:
	doubleNode<datatype> *p_prior;                         //指向前节点的指针
	doubleNode<datatype> *p_next;                          //指向后节点的指针
	datatype data;                                         //自身节点的数据
	int length;                                            //链表长度
	//定义友元类
	friend  class doubleLink<datatype>;
};
/***************************************双向链表定义*************************************************/
template<typename datatype>class doubleLink
{
public:
	//双向链表的构造函数,链表产生新头结点
	doubleLink()
	{
		head = new doubleNode<datatype>();                  //链表产生新头结点
	}
	//双向链表的构造函数,链表产生新头结点
	doubleLink(doubleNode<datatype>*note)
	{
		head = note;
	}
	//双向链表的析构函数,链表删除头节点
	~doubleLink()
	{
		delete head;
	}
public:
	void cleandoubleLink();                                 //清空双向链表
	int  getLength();                                       //获取链表长度
	int  findData(datatype item);                           //寻找给定数值的结点
	bool insertNode(datatype item,int n);                   //在i个结点插入datatype类型item
	bool deleteNode(int n);                                 //删除第i个结点的数据
	datatype getData(int n);                                //获取第i个结点的数据
private:
	doubleNode<datatype> * head;                            //头指针
};
/********************************************清空双向链表*************************************************/
template<typename datatype>
void doubleLink<datatype>::cleandoubleLink()
{
	doubleNode<datatype> *P_move = head->p_next, *P_middle;  //设置游标指针   
	while (P_move!=NULL)                                     //判断头指针后面的结点
	{
		P_middle = P_move;
		P_move = P_middle->p_next;                           //游标指针借助中间指针向后移
		delete P_middle;                                     //删除中间指针,即删除后面的结点
	}
	head->p_next = NULL;                                     //将头指针的指向空
}
/********************************************获取链表长度*************************************************/
template<typename datatype>
int doubleLink<datatype>::getLength()
{
	doubleNode<datatype> *P_move = head->p_next;             //设置游标指针
	int length=0;
	//遍历链表,计算结点数
	while(P_move!=NULL)
	{
		P_move = P_move->p_next;                            //游标指针后移
		length++;                                           //计算length
	}
	return length;
}
/***************************************寻找给定数值的结点*************************************************/
template<typename datatype>
int doubleLink<datatype>::findData(datatype item)
{
	doubleNode<datatype> *P_move = head;             //设置游标指针
	if (P_move->p_next==NULL)
	{
		cout << "当前链表为空链表!" << endl;
		return 0;
	}
	int length = 0;                     
	while (P_move->data!= item)
	{
		P_move = P_move->p_next;                             //游标指针后移
		length++;
	}
	return length;
}
/************************************在i个结点插入datatype类型item*****************************************/
template<typename datatype>
bool doubleLink<datatype>::insertNode(datatype item, int n)
{

  if (n<1)
  {
	cout << "输入非有效位置" << endl;
	return false;
		}
  doubleNode<datatype>  * P_move = head;             //创建新指针,并设置游标指针
  
  //找到插入位置
  for (int i = 1; i <n; i++)
  {
	  P_move = P_move->p_next;                                                                      //游标指针后移
	  if (P_move==NULL&&i<=n)
	  {
		  cout << "插入位置无效" << endl;
		  return false;
	  }
  }
  doubleNode<datatype> * newNode = new doubleNode<datatype>(item);
  //插入新结点
  if (newNode == NULL)
  {
	  cout << "内存分配失败,新结点无法创建" << endl;
	  return false;
  }
  newNode->p_next= P_move->p_next;   
  if (P_move->p_next!=NULL)
  {
	  P_move->p_next->p_prior = newNode;
  }
  newNode->p_prior = P_move;
  P_move->p_next = newNode;
  return true;
}
/***************************************删除第i个结点的数据*************************************************/
template<typename datatype>
bool doubleLink<datatype>::deleteNode(int n)
{
	if (n<1||n>getLength())
	{
		cout << "输入非有效位置" << endl;
		return false;
	}
	doubleNode<datatype> * P_move = head,* p_delete;             //设置游标指针
	//查找删除结点的位置
	for (int i = 1; i <= n; i++)
	{
		P_move = P_move->p_next;                                         //游标指针后移
	}
	//删除结点
	p_delete = P_move;      
	P_move->p_prior->p_next = p_delete->p_next;
	P_move->p_next->p_prior = p_delete->p_prior;
	delete p_delete;
	return true;
}
/***************************************获取第i个结点的数据*************************************************/
template<typename datatype>
datatype doubleLink<datatype>::getData(int n)
{
	if (n<1|| n>getLength())
	{
		cout << "输入非有效位置" << endl;
		return 0;
	}
	doubleNode<datatype> * P_move = head;             //设置游标指针
	for (int i = 1; i<=n; i++)
	{
		P_move = P_move->p_next;                                         //游标指针后移
	}
	if (P_move==NULL)
	{
		cout << "没有所要查找的结点" << endl;
		return 0;
	}
	return P_move->data;
}
/***************************************************主函数***************************************************/
int main()
{

	doubleNode<int> Note;
	doubleLink<int> Link(&Note);
	cout << "*******************************操作选择*******************************" << endl;
	cout << "1.产生链表" << endl;
	cout << "2.给链表中插入元素" << endl;
	cout << "3.删除链表中的元素" << endl;
	cout << "4.获取链表中的元素" << endl;
	cout << "5.获取链表中的数据位置" << endl;
	cout << "6.清空链表中的元素" << endl;
	cout << "**********************************************************************" << endl;
	while (1)
	{
		int Opera_Number;
		cin >> Opera_Number;
		switch (Opera_Number)
		{
			//产生链表
		   case 1:
		  {
			   int doubleLink_Number;
			   cout << "输入你需要的链表长度:" << endl;
			   cin >> doubleLink_Number;
			   for (int i = 1; i <=doubleLink_Number; i++)
			   {
				   Link.insertNode(i*11,i);
			   }
   cout << "*****************************当前链表为********************************" << endl;
			   for (int i = 1; i <=doubleLink_Number; i++)
			   {
				   cout << Link.getData(i) << "  ";
			   }
			   break;
		            }
		  //给链表中插入元素
		   case 2:
		   {
			   int insert_Number, insert_Data;
			   cout << "输入插入位置点:" << endl;
			   cin >> insert_Number;
			   cout << "输入插入数据:" << endl;
			   cin >> insert_Data;
			   Link.insertNode(insert_Data, insert_Number);
			   cout << "*****************************当前链表为********************************" << endl;
			   for (int i = 1; i <=( Link.getLength()); i++)
			   {
				   cout << Link.getData(i) << "   ";
			   }
			   break;
		   }
		   //删除链表中的元素
		   case 3:
		   {
			   int delete_Number;
			   cout << "输入删除位置点:" << endl;
			   cin >> delete_Number;
			   Link.deleteNode(delete_Number);
			   cout << "*****************************当前链表为********************************" << endl;
			   for (int i = 1; i <= (Link.getLength()); i++)
			   {
				   cout << Link.getData(i) << "  ";
			   }
			   break;
		   }
		   //获取链表中的元素
		   case 4:
		   {
			   int get_Number;
			   cout << "输入获取位置点:" << endl;
			   cin >> get_Number;
			   cout << "获取到的数据:" << Link.getData(get_Number) << endl;
			   break;
		   }
		  //获取链表中的数据位置
		   case 5:
		   {
			   int data;
			   cout << "输入想查询的数据:" << endl;
			   cin >> data;
			   if ((Link.findData(data)!=0))
			   {
				   cout << "该数据在链表中的位置为:" << Link.findData(data) << endl;
			   }
			   break;
		   }
		   //清空链表中所有的元素
		   case 6:
		   {
			   cout << "删除前的链表长度:" << Link.getLength() << endl;
			   Link.cleandoubleLink();
			   cout << "删除后的链表长度:" << Link.getLength() << endl;
			   break;
		   }
		   //未在操作数范围内
		   default:
		   {
			   cout << "输入操作数未在操作数范围内" << endl;
			   break;
		   }
		}
	}
	return 0;
}

代码在创建过程中,主要参照了由胡浩主编的《妙趣横生的算法》的搭建方式与搭建方法。在编程的过程中,我认为我遇到的比较核心的主要有两点:
1.游标指针的设置:通过游标指针的后移,可以帮助我们很方便的对结点从头结点后进行查找。
2.链表的插入、删除的基本算法的理解:插入与删除的基本算法说到底就是对前驱指针和后继指针的设置,只要将这两个指针域搞清楚了,基本操作也就掌握了。(ps:如果想详细了解,将insertNode函数、deleteNode函数多看几遍即可。)

零零散散就写这么多,程序自己亲自跑了一遍,感觉没什么太大的问题。大家如果看的过程中有什么问题,也欢迎大家相互交流!!

猜你喜欢

转载自blog.csdn.net/weixin_43165699/article/details/97281946