原型:单链表;
与单链表节点结构差异:单链表仅有一个指针域指向下一个节点,双链表有两个指针域分别指向其上一个和下一个节点;
实现操作差异:主要是上链(插入)与脱链(删除)操作,其中双链表上链时的指针重导向需注意相对顺序(不能颠倒)
节点结构:
#pragma once
template< typename T>
class Node {
public:
T data;
Node *next; //向后指针
Node *prior; //向前指针 相对单链表新增的指针域
};
双链表类模板实现:
#pragma once
#include"Node.h"
#include<iostream>
#include<string>
using namespace std;
template <typename T>
class doubleLink
{
public:
doubleLink(T a[],int n);
~doubleLink();
int Length(); //返回单链表的长度
T Get(int i); //按位查找,查找第i个节点的元素
int Locate(T x); //按值查找,查找链表中第一个值为x的元素,并返回序号
bool Insert(int i, T x); //插入元素,在第i个位置插入值x
bool Delete(int i); //删除节点,删除第i个节点
bool InsertHead(T x); //头插法插入节点
bool InsertTail(T x); //尾插法插入节点
void ListTraverse(); //遍历节点
T priorOne(int i); //返回节点的上一个节点
T nextOne(int i); //返回节点的下一个节点
private:
Node<T> *first; //设置头指针
int m_Length; //设置链的长度计数器
};
template<typename T>
doubleLink<T>::doubleLink(T a[], int n)
{
m_Length = 0;
first = new Node<T>;
first->next = NULL;
first->prior = NULL;
for (int i = 0; i < n; i++) //头插法插入元素
{
Node<T> *s = new Node<T>;
s->data = a[i];
if (first->prior == NULL) {
s -> next = first;
s->prior = first;
first->next = s;
first->prior = s;
m_Length++;
}
else {
s->next = first->next;
first->next->prior = s;
s -> prior = first;
first->next = s;
m_Length++;
}
}
//尾插法插入元素
/*for (var i = 0; i < n;i++) {
Node<T> *s = new Node<T>;
s->data = a[i];
if (first->prior == NULL) {
s->next = first;
s->prior = first;
first->next = s;
first->prior = s;
Length++;
}
else {
s->prior = first->prior;
s->next = first;
first->prior->next = s;
first->prior = s;
m_Length++;
}
}*/
}
template<typename T>
doubleLink<T>::~doubleLink()
{
while (first->next!=first->prior)
{
//临时指针,存储即将释放的节点的指针
Node<T> *temp = first;
//脱链
first->prior->next = first->next;
first->next -> prior = first->prior;
//头指针后移
first = first->next;
//释放内存
delete temp;
}
delete first;
}
template<typename T>
int doubleLink<T>::Length() {
return m_Length;
}
template<typename T>
T doubleLink<T>::Get(int i) {
if (i > m_Length || i <= 0)
{
throw string("调用函数Get()时位置出错!");
}
else {
Node<T> *p = first;
for (int j = 0; j < i;j++) {
p = p->next;
}
return p->data;
}
}
template<typename T>
int doubleLink<T>::Locate(T x) {
Node<T> *p = first->next;
int count = 1;
for (int i = 0; i < m_Length; i++) {
if (p->data == x)
{
return count;
}
p = p->next;
count++;
}
if (p->next == first)
{
return -1; /*个人认为此处不应该抛出错误,所以并没有throw*/
}
}
template<typename T>
bool doubleLink<T>::Insert(int i, T x) {
if (i > m_Length || i <= 0) { //判断要插入的位置是否在合理范围
throw string("调用函数Insert()时位置出错");
}
Node<T> *p = first;
Node<T> *s = new Node<T>;
if (s == NULL) {
return false;
}
s->data = x;
int count = 0;
while (p->next!=first&&count < i) {
p = p->next;
count++;
}
s->next = p;
s->prior = p->prior;
p->prior->next = s;
p->prior = s;
m_Length++;
return true;
}
template<typename T>
bool doubleLink<T>::Delete(int i) {
if (i > m_Length || i < 0)
{
throw string("调用函数Delete()时位置出错");
}
int count = 0;
Node<T> *p = first;
while (p->next != first&&count < i) {
p = p->next;
count++;
}
p->prior->next = p->next;
p->next->prior = p->prior;
delete p;
m_Length--;
return true;
}
template<typename T>
bool doubleLink<T>::InsertHead(T x) {
Node<T> *s = new Node<T>;
if (s == NULL) {
return false; //内存申请失败要不要throw出来?em......母鸡
}
s->data = x;
s->next = first->next;
s->prior = first;
first->next->prior = s;
first->next = s;
m_Length++;
return true;
}
template<typename T>
bool doubleLink<T>::InsertTail(T x) {
Node<T> *s = new Node<T>;
if (s == NULL) {
return false;
}
s->data = x;
s->next = first;
s->prior = first->prior;
first->prior->next = s;
first->prior = s;
m_Length++;
return true;
}
template<typename T>
void doubleLink<T>::ListTraverse() {
Node<T> *p = first->next;
cout << endl;
for (int i = 0; i < m_Length;i++) {
cout << p->data << ",";
p = p->next;
}
}
template<typename T>
T doubleLink<T>::priorOne(int i) {
if (i > m_Length || i <= 0)
{
throw string("调用函数prior时位置出错");
}
else {
Node<T> *p = first;
for (int j = 0; j < i; j++) {
p = p->next;
}
if (i == 1) {
return p->prior->prior->data;
}
else {
return p->prior->data;
}
}
}
template<typename T>
T doubleLink<T>::nextOne(int i) {
if (i > m_Length || i <= 0)
{
throw string("调用函数nextone时位置出错");
}
else {
Node<T> *p = first;
for (int j = 0; j < i; j++) {
p = p->next;
}
if (i==m_Length) {
return p->next->next->data;
}
else {
return p->next->data;
}
}
}
函数调用测试:
#include<iostream>
#include"doubleLink.h"
#include<string>
using namespace std;
int main() {
int a[5] = { 1,2,3,4,5 };
try{
doubleLink<int> MyList(a, 5);
MyList.ListTraverse(); //测试遍历函数是否成功
cout << endl << "链表长度为:" << MyList.Length() << endl; //测试返回长度函数是否成功
cout << "第1个节点的元素为:" << MyList.Get(1); //测试查找位置元素的函数是否成功
MyList.Delete(1);
cout << endl << "删除第一个节点后:";
MyList.ListTraverse();
MyList.Insert(1, 5);
cout <<endl<< "插入元素5到第一个节点后:" ;
MyList.ListTraverse();
MyList.InsertHead(2);
cout << endl << "头插法插入元素2:";
MyList.ListTraverse();
MyList.InsertTail(8);
cout << endl << "尾插法插入元素8";
MyList.ListTraverse();
cout << endl << "元素8所在的位置为:" << MyList.Locate(8);
cout << endl << "第二个节点的后一个节点元素为:" << MyList.nextOne(2);
cout << endl << "第二个节点的前一个节点元素为:" << MyList.priorOne(2);
}
catch (string &aval) {
cout << aval << endl;
}
return 0;
}
合法数据调用结果:
部分非法数据调用结果:
Get(i)传入的参数非法时:
Delete(i)传入的参数非法时:
在准备选择双链表时,应先看看单链表是否能够满足需求,因为双链表多了一个指针域,数据量大时可能会浪费存储空间,而且双链表操作比单链表繁琐一点。
额。。。
暂时只能挤这么多。。
Bye