双向循环链表的实现

来源:互联网 发布:知不足而自省 编辑:程序博客网 时间:2024/06/09 20:06

                双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。


#include<iostream>
using namespace std;

// 数据类型结构体

typedef int ElemType;

// 双向循环链表结构体

typedef struct _DualNode
{
    ElemType data;   // 存储的数据类型
    struct  _DualNode *prior;   // 指向结点的前驱
    struct  _DualNode *next;   // 指向结点的后继
}DualNode, *DuaLinkList;

// 初始化头节点

void InitDualLinkList(DuaLinkList *pHead)
{
    *pHead = new DualNode;
    if (NULL==*pHead)
    {
        return;
    }
    (*pHead)->prior=*pHead;
    (*pHead)->next = *pHead;
}

// 获取链表的长度

int GetDualLInkListLength(DuaLinkList pHead)
{
    int count = 0;
    DuaLinkList nPos = pHead;

    while (nPos->next!=pHead)
    {
        nPos = nPos->next;
        count++;
    }
    return count;
}

// 判读链表是否为空

bool IsEmpty(DuaLinkList pHead)
{
    if (pHead->next==pHead||pHead->prior==pHead)
    {
        return true;
    }
    else
    {
        return false;
    }
}

// 返回第i个元素的值

ElemType GetElem(DuaLinkList pHead,int index)
{

    if (index<=0||index>GetDualLInkListLength(pHead))
    {
        return -1;
    }


    for (int i = 0; i<index; i++)
    {
        pHead = pHead->next;
    }
    return pHead->data;
}

// 销毁头节点函数

void DestroyHeadDNode(DuaLinkList *pHead)
{
    delete *pHead;
    *pHead = NULL;

}

// 头插法建表

void InsertHeadDualLinkList(DuaLinkList *pHead, ElemType value)
{
    DuaLinkList pNew = new DualNode;
    
    if (NULL==pNew)
    {
        return;
    }
    pNew->data = value;

    if (*pHead ==(*pHead)->next|| *pHead ==(*pHead)->prior)
    {
        (*pHead)->next = pNew;
        (*pHead)->prior = pNew;
        pNew->next = (*pHead);
        pNew->prior = (*pHead);
    }
    else
    {
        (*pHead)->next->prior = pNew;
        pNew->next = (*pHead)->next;
        (*pHead)->next = pNew;
        pNew->prior = (*pHead);
    }
}

// 尾插法建表

void InsertTailDualLinkList(DuaLinkList *pHead, ElemType value)
{

    if ((*pHead)->next==*pHead||(*pHead)==(*pHead)->prior)
    {
        InsertHeadDualLinkList(pHead,value);
    }
    else
    {
        DuaLinkList pNew = new DualNode;
        if (NULL == pNew)
        {
            return;
        }
        pNew->data = value;
        
        pNew->prior = (*pHead)->prior;
        (*pHead)->prior->next = pNew;
        pNew->next = *pHead;
        (*pHead)->prior = pNew;
    }
}

// 双向链表按下标插入元素

void  InsertByIndex(DuaLinkList *pHead,int pos, ElemType value)
{
    if (0==pos)
    {
        return;
    }
    if (pos>GetDualLInkListLength(*pHead))
    {
        InsertTailDualLinkList(pHead,value);
        return;
    }
    //if (1==pos)
    //{
    //    InsertHeadDualLinkList(pHead,value);
    //    return;
    //}

    DuaLinkList nPos = *pHead;
    for (int i = 0; i < pos; i++)
    {
        nPos = nPos->next;
    }

    DuaLinkList pNew = new DualNode;
    if (NULL==pNew)
    {
        return;
    }
    pNew->data = value;
    
    DuaLinkList temp = nPos;
    pNew->prior = temp->prior;
    temp->prior->next = pNew;
    pNew->next =temp;
    temp->prior = pNew;
}

// 返回第i个元素的地址

DuaLinkList GetElemAddress(DuaLinkList *pHead,int index)
{
    if (index<=0||index>GetDualLInkListLength(*pHead))
    {
        return NULL;
    }

    DuaLinkList nPos = *pHead;
    for (int i = 0; i < index; i++)
    {
        nPos = nPos->next;
    }
    return nPos;
}

// 正向显示函数

void ShowDuaLinkList(DuaLinkList pHead)
{
    DuaLinkList nPos = pHead;
    while (nPos->next!=pHead)
    {
        nPos = nPos->next;
        cout << nPos->data<<"   ";
    }
    cout << endl;
}

// 逆向显示函数

void ReverseShowDualLinkList(DuaLinkList pHead)
{
    DuaLinkList nPos = pHead;
    while (pHead!= nPos->prior)
    {
        nPos = nPos->prior;
        cout << nPos->data << "   ";

    }
    cout << endl;
}


     我在前面两篇博客《经典算法学习——单链表(不带头结点)实现冒泡排序》《经典算法学习——单链表实现冒泡排序(带头结点)》中详细描述了分别使用带头结点和不带头结点的单链表实现了冒泡排序,让我们对单链表和冒泡排序有了理性的认识。今天我们将会来使用不带头结点的非循环双向链表来实现冒泡排序,在处理过程中,这种冒泡比前面两种更为简单高效。


// 双向链表的冒泡排序


void BubleSort(DuaLinkList *pHead)
{
    DuaLinkList nPos = (*pHead)->next;

    int len = GetDualLInkListLength(*pHead);

    while (len>1)
    {
        while (nPos->next!=*pHead)
        {
            if (nPos->data>nPos->next->data)
            {
                ElemType temp;
                temp = nPos->data;
                nPos->data = nPos->next->data;
                nPos->next->data = temp;

            }
            nPos = nPos->next;
        }
        len--;
        nPos = (*pHead)->next;
    }
}

// 头删函数

void DeleteHeadDuaLinkList(DuaLinkList *pHead)
{
    if ((*pHead)->next != *pHead || (*pHead)->prior != *pHead)    //  判断是否只剩下一个头节点
    {
        DuaLinkList  temp = (*pHead)->next;   // 用临时变量来标记头结点后的第一个节点;
        (*pHead)->next = temp->next;    // 头节点指向删除后的第一个结点
        temp->next->prior = (*pHead);   // 删除后链表的第一个结点的前驱指针指向头节点;
        delete temp;
        temp = NULL;
    }
}

// 尾删函数

void DelTailDualLinkList(DuaLinkList *pHead)
{
    if ((*pHead)->next != *pHead || *pHead != (*pHead)->prior)   //  判断是否只剩下一个头节点
    {
        DuaLinkList temp = (*pHead)->prior;          // 用临时变量来标记头结点所指向的倒数第一个节点;
        
        temp->prior->next=(*pHead);   // 链表中的倒数第一个结点指向头节点;
        (*pHead)->prior = temp->prior;   // 头节点的前驱指针指向倒数第二结点;

        delete temp;     // 释放倒数第一个结点的内存;
        temp= NULL;   
    }
}

// 删除双向链表中第 i 个元素

void DelElemByIndex(DuaLinkList *pHead, int index)
{
    if (index <= 0 || 0 == GetDualLInkListLength(*pHead))
    {
        return;
    }

    if (index>GetDualLInkListLength(*pHead))
    {
        DelTailDualLinkList(pHead);
    }
    else
    {
        DuaLinkList nPos = *pHead;
        for (int i = 0; i < index; i++)
        {
            nPos = nPos->next;
        }
        DuaLinkList temp = nPos;   // 用临时变量记住所要删除的元素

        nPos->prior->next = temp->next;   // 所要删除元素的前一个结点指向删除元素的后继元素
        temp->next->prior = nPos->prior;    // 删除元素的后继元素的前驱指向删除元素的前驱结点
        delete temp;
        temp = NULL;
    }

}

// 清空双向链表(保留头节点)

void ClearDuaLinkList(DuaLinkList *pHead)
{
    DuaLinkList nPos = *pHead;
    while (nPos->next != *pHead || *pHead != nPos->prior)
    {
        DelTailDualLinkList(pHead);
    }
}

// 销毁双向链表(包含销毁头节点)

void DestoryDuaLinkList(DuaLinkList *pHead)
{
    if (*pHead!=(*pHead)->next||*pHead!=(*pHead)->prior)
    {
        ClearDuaLinkList(pHead);
    }
    DestroyHeadDNode(pHead);
}

注:  写冒泡排序真的很蛋疼,想了半天写不出来,而且进行指针间的交换并不高效,于是就在博客上查资料,看到 交换值这种简单高效的办法,所以就采用了此办法,由于博主知识和技术水平有限,请读者见谅

0 0