数据结构:双向链表(带头双向循环链表).

带头:链表的头节点不存储有效数据

双向:链表结构体中存在两个指针,分别指向链表的前后两个节点

循环:链表的尾节点指向头节点,形成循环

当双向链表只有头节点时,该链表为空链表

头节点不能进行删除或修改

//定义双向链表中节点的结构
typedef int LTDataType;
typedef struct ListNode
{
    int data;
    struct ListNode* prev;
    struct ListNode* next;
}LTNode;

一.双向链表的初始化

LTNode* LTBuyNode(LTDataType x)
{
    LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
    if(newnode == NULL)
    {    
        perror("malloc fail");
        exit(1);
    }

    newnode->data = x;
    newnode->next = newnode->prev = newnode;

    return newnode;
}

LTNode* LTInit(LTNode** pphead)
{
    LTNode* phead = LTBuyNode(-1);//传入-1表示头节点存储的数据无效,-1可以改成任意数字,无实际意义
    return phead;
}

二.双向链表的销毁

方法一:

void LTDestory(LTNode** pphead)
{
    assert(pphead);
    assert(*pphead);
    
    //释放头节点以外的节点
    LTNode* pcur = (*pphead)->next;
    while(pcur != *pphead)
    {
        LTNode* next = pcur->next;
        free(pcur);
        pcur = next;    
    }

    //释放头节点
    free(*pphead);
    *pphead = NULL;
}

方法二:

void LTDestory(LTNode* phead)
{
    assert(phead);

    
    //释放头节点以外的节点
    LTNode* pcur = phead->next;
    while(pcur != phead)
    {
        LTNode* next = pcur->next;
        free(pcur);
        pcur = next;    
    }

    //释放头节点
    free(phead);
    phead = NULL;
}

//由于传入的是值而非地址,因此在函数调用完成后,phead并未为空,需要后续手动置为空
int main()
{
...
    phead = NULL;
...
}

三.双向链表的尾插


void LTOPushBack(LTNode* phead,SLDataType x)//因为头节点不能修改,因此只需要传入一级指针
{
    //头节点不为空
    assert(phead);
    LTNode* phead = LTBuyNode(x);
    //修改新节点指向
    newnode->next = phead;
    newnode->prev = phead->prev;
    //修改尾节点指向
    phead->prev->next = newnode;
    //修改头节点指向
    phead->prev = newnode;
}

四.双向链表的头插

void LTOPushFront(LTNode* phead,SLDataType x)
{
    assert(phead);
    LTNode* phead = LTBuyNode(x);

    newnode->next = phead->next;
    newnode->prev = phead;

    phead->next->prev = newnode;
    
    phead->next = newnode;
}

五.双向链表的打印

void LTPrint(LTNode* phead,LTDataType x)
{
    LTNode* pcur = phead->next;
    while(pcur != phead)
    {
        printf("%d->",pcur->data);
        pcur = pcur->next;
    }
}

六.双向链表的尾删

void LTPopBack(LTNode* phead)
{
    assert(phead);
    assert(phead->next != phead);//如果头节点的next和prev指向自己,则当前链表为空
    
    LTNode* del = phead->prev;
    LTNode* prev =  del->prev;
    
    prev->next = phead;
    phead->prev = prev;
    
    free(del);
    del = NULL;
}

七.双向链表的头删

void LTPopFront(LTNode* phead)
{
    assert(phead);
    assert(phead->next != phead);//如果头节点的next和prev指向自己,则当前链表为空

    LTNode* del = phead->next;
    LTNode* next = del->next;

    next->prev = phead;
    phead->next = next;
    
    free(del);
    del = NULL;
}

八.双向链表的查找

LTNode* LTFind(LTNode* phead,LTDatatype x)
{
    assert(phead);
    LTNode* pcur = phead->next;
    while(pcur != phead)
    {
        if(pcur->data == x)
        {
            return pcur;
        }
        pcur = pcur->next;
    }
    return NULL;
}    

 九.在特定位置之后插入数据

void LTInsert(LTNode* pos,LTDataType x)
{
    assert(pos);
    LTNode* newnode = LTBuyNode(x);
    
    newnode->next = pos->next;
    newnode->prev = pos;

    pos->next->prev = newnode;
    pos->next = newnode;
}

十.删除特定位置数据

void LTErase(LTNode* pos)
{
    assert(pos);

    pos->next->prev = pos->prev;
    pos->prev->next = pos->next;

    free(pos);
    pos = NULL;
}

你可能感兴趣的:(数据结构,链表)