定义了两个头文件分别放置结点类模板(Node.h)和双链表模板(DoubleLinkList.h),
然后在源文件的main函数中测试。
Node.h
#pragma once
# include
template
class Node
{
public:
DataType data;
Node *prior;
Node *next;
Node();
Node(DataType data_, Node *prior_, Node *next_);
};
template
Node::Node()//定义一个空结点
{
prior = NULL;
next = NULL;
}
template
Node::Node(DataType data_, Node *prior_ , Node *next_ )//定义一个完整结点
{
prior = prior_;
next = next_;
data = data_;
}
DoubleLinklist.h
/*
实现双向循环链表
实现的运算操作有
增 ,删 ,改 ,查
初始化, 清空 ,求线性表长度
*/
#include "Node.h"
using namespace std;
template
class DoubleLinkList
{
int length;
Node *head;
public:
DoubleLinkList();//初始化————初始化一个空表,
DoubleLinkList(const DataType data_[],int n);//初始化————初始化一个含有数据的表
void Insert(const DataType data_, int pos);//增————向某个位置pos之前插入一个数据data_
void Delete(int pos);//删————删除某个位置pos处的结点
void Change(const DataType data_,int pos);//改————改动某个位置pos处的结点
DataType Search1(int pos);//查————根据下标查数据
int Search2(const DataType &e);//查————根据数据查下标
void Clear();//清空————仅保留头节点
int GetLength();//得到长度
void PrintAll();//遍历链表输出各节点数值
~DoubleLinkList();//析构————删除所有结点,释放所有指针
};
//初始化————初始化一个空表(只有头节点)
template
DoubleLinkList::DoubleLinkList()
{
head = new Node; //动态分配一个空结点,即头节点
assert(head);
head->prior = head;//头节点的首指针指向其本身
head->next = head;//头节点的尾指针指向其本身
length = 0;
}
//初始化————初始化一个含有数据的表
//实参用数组传入要写入的数据
//由于C++中没有自带直接求数组长度的函数
//所以需要手动把数组的长度n写进去
template
DoubleLinkList::DoubleLinkList(const DataType data_[],int n)
{
head = new Node; //动态分配一个空结点,即头节点
Node *p = head;//创建一个指向结点的指针p后面将用这个指针遍历,实现不断的加数据结点
for (int i = 0; i < n; i++) {
//这两行代码其实包含了四个操作
//step1 :new运算符建立下一个结点 且通过构造函数将数据域赋值为data_[i]
//step2:通过构造函数将该结点的首指针指向p(即上一个节点) 尾指针指向NULL
//step3:通过赋值运算符将上一个结点的尾指针指向下一个结点
//step4 将指针p移动至下一个结点 以便下一步的迭代
p->next = new Node(data_[i], p,NULL);
p = p->next;
}
length = n;
p->next = head;
head->prior = p;
}
//增————向某个位置pos插入一个数据data_
template
void DoubleLinkList::Insert(const DataType data_, int pos)
{
//step0:准备工作 建立要遍历的指针p和新建要插入的数据结点add
Node *p = head;//创建一个指向结点的指针p后面将用这个指针遍历
Node *add = new Node(data_, NULL, NULL);//建立一个新结点,包含要插入的数据data_
//step1:判断插入位置是否正确
if (pos<1 || pos>length+1)
{
std::cout << "插入数据失败" << endl;
}
else
{
//step2,用指针p进行遍历,直到达到指定位置
int i;
for(i = 0; i < pos; i++)
{
p = p->next;
}
//step3 ,开始插入
add->prior = p->prior;
p->prior->next = add;
p->prior = add;
add->next = p;
length += 1;
std::cout << "插入数据成功" << endl;
}
}
//删————删除某个位置pos的结点
template
void DoubleLinkList::Delete(int pos)
{
//step0:准备工作 建立要遍历的指针p和新建要插入的数据结点add
Node *p = head;//创建一个指向结点的指针p后面将用这个指针遍历
//step1:判断删除位置是否正确
if (pos<1 || pos>length)
{
std::cout << "删除数据失败" << endl;
}
else
{
int i;
for(i = 0; i < pos; i++)
{
p = p->next;
}
//step2:开始删除
p->prior->next = p->next;
p->next->prior = p->prior;
length = length - 1;
std::cout << "删除数据成功" << endl;
delete p;//千万注意此处要delete指针p!
}
}
//改————改动某个位置pos处的结点
template
void DoubleLinkList::Change(const DataType data_,int pos)
{
//step0:准备工作 建立要遍历的指针p和新建要改动的数据结点add
Node *p = head;//创建一个指向结点的指针p后面将用这个指针遍历
//step1:判断插入位置是否正确
if (pos<1 || pos>length + 1)
{
std::cout << "改动数据失败" << endl;
}
else
{
int i;
//step2,用指针p进行遍历,直到达到指定位置
for(i = 0; i < pos; i++)
{
p = p->next;
}
//step3 ,开始改动
Node *change = new Node(data_, p->prior, p->next);//建立一个新结点,包含要改动的数据data_
p->prior->next = change;
p->next->prior = change;
std::cout << "改动数据成功" << endl;
delete p;//千万注意此处要delete指针p!
}
}
//查————根据下标查数据
template
DataType DoubleLinkList::Search1(int pos)
{
//step0:准备工作 建立要遍历的指针p
Node *p = head;//创建一个指向结点的指针p后面将用这个指针遍历
//step1:判断查找位置是否正确
if (pos<1 || pos>length)
{
std::cout << "查找数据失败" << endl;
return 0;
}
else
{
int i;
for(i = 0; i < pos; i++)
{
p = p->next;
}
//step2:返回查找数据
return p->data;
std::cout << "查找数据成功" << endl;
}
}
//查————根据数据查下标
template
int DoubleLinkList::Search2(const DataType &e)
{
//step0:准备工作 建立要遍历的指针p
Node *p = head;//创建一个指向结点的指针p后面将用这个指针遍历
//step1:开始查找
int i = 0;
while((idata != e))
{
i++;
p = p->next;
}
if (p == head)
{
return 0;
std::cout << "找不到该数据" << endl;
}
else
{
return i;
std::cout << "成功找到该数据" << endl;
}
}
//清空
template
void DoubleLinkList::Clear()
{
int i = 0;
while (i < length)
{
i++;
Delete(1);
}
length = 0;
}
//析构
template
DoubleLinkList::~DoubleLinkList()
{
Clear();
delete head;
cout << "析构函数已执行" << endl;
}
//求线性表长度
template
int DoubleLinkList::GetLength()
{
return length;
}
//遍历输出
template
void DoubleLinkList::PrintAll()
{
int i;
Node *p = head;//创建一个指向结点的指针p后面将用这个指针遍历
cout << "该链表的所有数据如下" << endl;
for (i = 0; i < length; i++)
{
p = p->next;
cout << p->data << " ";
}
}
main
#include "DoubleLinkList.h"
#include
int main()
{
int data[4] = { 2, 3, 4, 12};
DoubleLinkList list(data, 4);//初始化
list.PrintAll();
cout << "线性表的长度为" << list.GetLength() << endl;//获取链表的长度
list.Insert(62,4);//增
list.PrintAll();
list.Delete(3);//删
list.PrintAll();
list.Change(35, 1);//改
list.PrintAll();
int data1 = list.Search1(3);
int pos1 = list.Search2(35);
cout << "链表中位置3处的数据为 " << data1 << "数据35在链表中的位置为 " << pos1;//查
while (1);
}
总结出现过的小问题:
1.定义链表模板类的时候
除了构造函数,其他成员函数中不要初始化头节点head = new Node
因为这样会导致该函数后面的指针p指针指向新的head,即变成空指针,无法指向链表头节点。
2.要注意输入过程中输入法中英文的切换 ,经常出现中文的括号,特别不易察觉。
3.在类模板的成员函数定义时 ,
如template
DoubleLinkList
最好使用typename关键字 用class可能会报错