雙鏈表( 初始化,建立,插入,查找,刪除 )


雙向鏈表和單向鏈表也是有很多相似的地方的,聽名字可以猜到,每個節點都包含兩個指針,一個指針指向上一個節點,一個指針指向下一個節點。這里有兩個特殊的地方,第一就是頭節點的一個指針指向NULL空指針(沒有前驅節點),第二就是尾節點的一個指針指向NULL指針(沒有后繼節點)。

 

#ifndef DOUBLY_LINKED_LIST_H
#define DOUBLY_LINKED_LIST_H

typedef struct Node
{
    int data;
    struct Node *pNext;
    struct Node *pPre;
}NODE, *pNODE;

//創建雙向鏈表
pNODE CreateDbLinkList(void);

//打印鏈表
void TraverseDbLinkList(pNODE pHead);

//判斷鏈表是否為空
int IsEmptyDbLinkList(pNODE pHead);

//計算鏈表長度
int GetLengthDbLinkList(pNODE pHead);

//向鏈表插入節點
int InsertEleDbLinkList(pNODE pHead, int pos, int data);

//從鏈表刪除節點
int DeleteEleDbLinkList(pNODE pHead, int pos);

//刪除整個鏈表,釋放內存
void FreeMemory(pNODE *ppHead);

#endif

DbLinkList.cpp 雙向鏈表的源文件——包含了各種操作函數的定義。

 

(1)這部分是創建雙向鏈表,和單向鏈表很相似,但是呢,有些地方還是得注意,就是每創建一個節點的時候都要注意初始化它的兩個指針。

#include <stdio.h>
#include <stdlib.h>
#include "DbLinkList.h"

//創建雙向鏈表
pNODE CreateDbLinkList(void)
{
    int i, length = 0, data = 0;
    pNODE pTail = NULL, p_new = NULL;
    pNODE pHead = (pNODE)malloc(sizeof(NODE));

    if (NULL == pHead)
    {
        printf("內存分配失敗!\n");
        exit(EXIT_FAILURE);
    }
    
    pHead->data = 0;
    pHead->pPre = NULL;
    pHead->pNext = NULL;
    pTail = pHead;

    printf("請輸入想要創建鏈表的長度:");
    scanf("%d", &length);

    for (i=1; i<length+1; i++)
    {
        p_new = (pNODE)malloc(sizeof(NODE));

        if (NULL == p_new)
        {
            printf("內存分配失敗!\n");
            exit(EXIT_FAILURE);
        }

        printf("請輸入第%d個元素的值:", i);
        scanf("%d", &data);

        p_new->data = data;
        p_new->pNext = NULL;
        p_new->pPre = pTail;
        pTail->pNext = p_new;
        pTail = p_new;
    }

    return pHead;
}

(2)這部分是獲得雙向鏈表的信息,這里和單向鏈表基本一致,因為遍歷的時候只用到了一個指針。

//打印鏈表
void TraverseDbLinkList(pNODE pHead)
{
    pNODE pt = pHead->pNext;

    printf("打印鏈表如:");
    while (pt != NULL)
    {
        printf("%d ", pt->data);
        pt = pt->pNext;
    }
    putchar('\n');
}

//判斷鏈表是否為空
int IsEmptyDbLinkList(pNODE pHead)
{
    pNODE pt = pHead->pNext;

    if (p == NULL)
        return 1;
    else
        return 0;
}

//計算鏈表的長度
int GetLengthDbLinkList(pNODE pHead)
{
    int length = 0;
    pNODE pt = pHead->pNext;

    while (pt != NULL)
    {
        length++;
        pt = pt->pNext;
    }
    return length;
}

(3)這部分是向雙向鏈表插入節點,也跟單向鏈表很多相似的地方。

每次我們添加一個節點都有很多地方要調節的,也就是每個節點的那兩個指針,一定要認真仔細自己動手寫一遍,有可能有些細節就會出錯。這里有一個地方需要注意,是和單向鏈表不同的地方,單向鏈表在插入節點的時候不需要判斷最后一個節點是否為空,因為這不影響程序的結果,但是對於雙向鏈表就不一樣了,因為我們后面要用到最后一個節點的一個指針指向前一個節點,如果最后一個節點是空的話(就是程序中的pt),就不存在pt->pPre了,那么程序運行到這里時就會報錯,所以我們要加個判斷,判斷此時節點是NULL的話就不需要控制它的指針了。

//向雙向鏈表中插入節點
int InsertEleDbLinkList(pNODE pHead, int pos, int data)
{
    pNODE pt = NULL, p_new = NULL;

    if (pos > 0 && pos < GetLengthDbLinkList(pHead)+2)
    {
        p_new = (pNODE)malloc(sizeof(NODE));

        if (NULL == p_new)
        {
            printf("內存分配失敗!\n");
            exit(EXIT_FAILURE);
        }

        while (1)
        {
            pos--;
            if (0 == pos)
                break;
            pHead = pHead->pNext;
        }
        
        pt = pHead->pNext;
        p_new->data = data;
        p_new->pNext = pt;
        if (NULL != pt)
            pt->pPre = p_add;
        p_new->pPre = pHead;
        pHead->pNext = p_new;
        
        return 1;
    }
    else
        return 0;
}

(4)這部分是從鏈表中刪除節點,當然這里和單向鏈表差不多,要注意的地方和插入節點時是一樣的,上面已經說明了。

//從鏈表中刪除節點
int DeleteEleDbLinkList(pNODE pHead, int pos)
{
    pNODE pt = NULL;

    if (pos > 0 && pos < GetLengthDbLinkList(pHead) + 1)
    {
        while (1)
        {
            pos--;
            if (0 == pos)
                break;
            pHead = pHead->pNext;
        }

        pt = pHead->pNext->pNext;
        free(pHead->pNext);
        pHead->pNext = pt;
        if (NULL != pt)
            pt->pPre = pHead;

        return 1;
    }
    else
        return 0;
}

(5)這部分是用來釋放內存的,注意的地方和上面一樣。

//刪除整個鏈表,釋放內存
void FreeMemory(pNODE *ppHead)
{
    pNODE pt = NULL;

    while (*ppHead != NULL)
    {
        pt = (*ppHead)->pNext;
        free(*ppHead);
        if (NULL != pt)
            pt->pPre = NULL;
        *ppHead = pt;
    }
}

main.cpp 測試程序源文件——通過簡單的交互信息來測試各個函數功能是否正確。

#include <stdio.h>
#include <stdlib.h>
#include "DbLinkList.h"

int main(void)
{
    int flag = 0, length = 0;
    int position = 0, value = 0;
    pNODE head = NULL;

    head = CreateDbLinkList();

    flag = IsEmptyDbLinkList(head);
    if (flag)
        printf("雙向鏈表為空!\n");
    else
    {
        length = GetLengthDbLinkList(head);
        printf("雙向鏈表的長度為:%d\n", length);
        TraverseDbLinkList(head);
    }

    printf("請輸入要插入節點的位置和元素值(兩個數用空格隔開):");
    scanf("%d %d", &position, &value);
    flag = InsertEleDbLinkList(head, position, value);
    if (flag)
    {
        printf("插入節點成功!\n");
        TraverseDbLinkList(head);
    }    
    else
        printf("插入節點失敗!\n");

    flag = IsEmptyDbLinkList(head);
    if (flag)
        printf("雙向鏈表為空,不能進行刪除操作!\n");
    else
    {
        printf("請輸入要刪除節點的位置:");
        scanf("%d", &position);
        flag = DeleteEleDbLinkList(head, position);
        if (flag)
        {
            printf("刪除節點成功!\n");
            TraverseDbLinkList(head);
        }    
        else
            printf("刪除節點失敗!\n");
    }

    FreeMemory(&head);
    if (NULL == head)
        printf("已成功刪除雙向鏈表,釋放內存完成!\n");
    else
        printf("刪除雙向鏈表失敗,釋放內存未完成!\n");

    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM