理论基础 —— 线性表 —— 双向链表

【实现类】

template <class T>
struct Node{//结点
    T data;//数据域
    Node *llink;//左指针
    Node *rlink;//右指针
};
 
template <class T>
class doubleList{
private:
    Node<T> *first;//头指针
public:
    doubleList();//无参构造函数
    doubleList();//有参构造函数
    ~doubleList();//析构函数
    void insertElement(T x);//在双链表中插入值为x的元素
    T deleteElement(T x);//删除双链表中值为x的元素
    void Sort(int len);//冒泡排序
    void print();//按序号依次输出双链表各元素
};

【构造函数】

1.无参构造函数

对于无参构造函数,只需建一个头结点,令其左右指针分别为空即可

template <class T>
linkList<T>::doubleLink(){//无参构造函数
    first=new Node<T>;//头指针指向头结点
    first->llink=NULL;//左指针为空
    first->rlink=NULL;//右指针为空
}

2.有参构造函数

1)头插法

template <class T>
linkList<T>::doubleLink(T a[],int n){
    first=new Node;//头指针指向头结点
    first->llink=NULL;//左指针为空
    first->rlink=NULL;//右指针为空

    Node *s;//新结点
    for(int i=1;i<=n;i++){
        s=new Node;
        s->data=a[i];//数据域
        s->rlink=first->rlink;
        first->rlink=s;
        s->llink=first;
        if(s->rlink!=NULL)//下个结点不为空
            s->rlink->llink=s;//下一个节点指向自己
    }
}

2)尾插法 

template <class T>
linkList<T>::doubleLink(T a[],int n){
    first=new Node<T>;//头指针指向头结点
    Node *r=first;//尾指针
    first->llink=NULL;//左指针为空
    first->rlink=NULL;//右指针为空

    Node<T> *s;//新结点
    for(int i=0;i<n;i++){
        s=new Node<T>;
        s->data=a[i];//数据域
        r->rlink=s;
        s->llink=r;
        r=s;
    }
    r->rlink=NULL;
}

【析构函数】

对于析构函数,与单链表的析构函数相同,仅需使用右指针 rlink 不断指向下一结点,释放存储空间即可

template <class T>
doubleLink<T>::~doubleLink(){
    Node<T> *p,*q;//工作指针
    p=first;//从头开始
    while(p!=NULL){
        q=p->rlink;//指向下一结点
        delete p;//释放当前结点空间
        p=q;//令当前节点指向下一结点
    }
}

【插入】

在双向链表中插入一个结点,对指针的操作顺序有很多,但由于双向链表实质上可看作两条反向的单链表,所以插入操作的核心是:先处理每个方向的远端指针,再处理近端指针

原则上,插入一个结点需要连接 4 个指针,但考虑插入时的特殊情况,即在空表或表尾插入一个结点时,新结点的右指针指向为空,此时只需连接 3 个指针

void doubleList<T>:: insertElement(T x){//在双表中插入值为x的元素
    Node<T> *s=new Node<T>;//新结点
    s->data=x;//新结点数据域赋值为x
    s->rlink=p->rlink;//新结点s的右指针指向工作结点p之后的结点
    s->llink=p;//新结点s的左指针指向工作结点p
    p->rlink=s;//工作结点p的右指针指向新结点s
    if(s->rlink!=NULL)//不为表尾或空时
        s->rlink->llink=s;//新结点s的右指针的左指针指向新结点s
}

【删除】

对于删除操作,其与插入操作相似,在删除时需要判断是否为表尾结点

bool doubleList<T>::deleteElement(T x){//删除双链表中值为x的元素
    Node<T> *p;//工作指针
    p=first->rlink;
    while(p!=NULL){
        if(p->data==x){
            if(p->rlink==NULL)//p为表尾元素
                p->llink->rlink=NULL;
            else{//p不为表尾元素
                p->llink->rlink=p->rlink;
                p->rlink->llink=p->llink;
            }
            delete p;//释放空间
            return true;//删除成功
        }
        p=p->rlink;
    }
    return false;//删除失败
}

【冒泡排序】

int doubleList<T>::void Sort(int len){//冒泡排序
    Node<T> *p;//工作指针
    for(int i=0;i<len-1;i++){//len-1轮
        p=first->rlink;
        for(int j=0;j<len-i-1;j++){//len-i次
            T tempA=p->data;//当前数据
            T tempB=p->rlink->data;//下一结点数据
            if(tempA>tempB){//比较
                T temp=p->data;
                p->data=p->rlink->data;
                p->rlink->data=temp;
            }
            p=p->rlink;//指向下一结点
        }
    }
}

【输出】

双链表的遍历输出,与单链表相同,仅需使用右指针 rlink 不断指向下一结点,输出数据域即可

template <class T>
void doubleLink<T>::print(){
    Node<T> *p;//工作指针
    p=first->rlink;//从第一个结点开始
    while(p!=NULL){
        cout<<(p->data)<<endl;//输出数据域
        p=p->rlink;//指向下一结点
    }
}

 

posted @ 2022-09-20 22:57  老程序员111  阅读(27)  评论(0)    收藏  举报