版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
利用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函数多看几遍即可。)
零零散散就写这么多,程序自己亲自跑了一遍,感觉没什么太大的问题。大家如果看的过程中有什么问题,也欢迎大家相互交流!!