c++数据结构:线性表实现之双链表

来源:互联网 发布:淘宝图片轮播怎么做 编辑:程序博客网 时间:2024/05/16 04:54

原型:单链表;
与单链表节点结构差异:单链表仅有一个指针域指向下一个节点,双链表有两个指针域分别指向其上一个和下一个节点;
实现操作差异:主要是上链(插入)与脱链(删除)操作,其中双链表上链时的指针重导向需注意相对顺序(不能颠倒)


节点结构:

#pragma oncetemplate< 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