單鏈表的增、刪、查、改

單鏈表是一種鏈式存取的數據結構,用申請的地址存放每個節點,這些地址可能是連續,也可能是不連續的。每個結點的構成:元素(數據元素的映象,data) + 指針(指示後繼元素存儲位置,next)。通過指針將線性表的數據一個個串聯起來,要想訪問一個數據,就要知道前一個指針,想知道前一個就要知道前前一個,依次向前找。所以,一般訪問是從頭指針開始向後查找目標,方向是單向的。

頭指針一般是固定的,而尾指針隨着鏈表的增加或刪除可能會改變,但是尾指針的後繼節點一定是指向空,即NULL的。

下面便是單鏈表的增、刪、查、改操作。

SingleLinkedList.h(頭文件)

#pragma once

#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<Windows.h>

typedef int DataType;

typedef struct SListNode
{
    struct SListNode* _next;
    DataType _data;
}SListNode;

SListNode* pStructInit();//結構體指針初始
SListNode* BuySListNode(DataType x);//創建節點
void SListPrint(SListNode* pHead);//打印
void SListDestory(SListNode** ppHead);//銷燬

void SListPushBack(SListNode** ppHead, DataType x);//尾插
void SListPopBack(SListNode** ppHead);//尾刪
void SListPushFront(SListNode** ppHead, DataType x);//頭插
void SListPopFront(SListNode** ppHead);//頭刪
SListNode* SListFind(SListNode* pHead, DataType x);//查找
void SListInsert(SListNode** ppHead, SListNode* pos, DataType x);//pos前插入
void SListErase(SListNode** ppHead, SListNode* pos);//pos位置刪除
void SListAt(SListNode** ppHead, SListNode *pos, DataType x);//替換

SingleLinkedList.c(功能函數的實現)

#include"SingleLinkedList.h"


SListNode* pStructInit()//結構體指針初始
{
    SListNode* pStruct = (SListNode*)malloc(sizeof(SListNode));

    if (pStruct == NULL)
    {
        perror("Initialize fail");
        exit(1);
    }

    pStruct->_next = NULL;

    return pStruct;
}

SListNode* BuySListNode(DataType x)//創建節點
{
    SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
    if (tmp == NULL)
    {
        perror("Malloc fail");
        exit(1);
    }

    tmp->_data = x;
    tmp->_next = NULL;

    return tmp;
}

void SListPrint(SListNode* pHead)//打印單鏈表
{
    assert(pHead);

    SListNode* pnode = pHead->_next;
    while (pnode)
    {
        printf("%d ", pnode->_data);
        pnode = pnode->_next;
    }
    printf("\n");
}

void SListDestory(SListNode** ppHead)//銷燬
{
    SListNode* tmp = NULL;

    while (*ppHead)
    {
        tmp = (*ppHead)->_next;
        free(*ppHead);
        (*ppHead) = tmp; 
    }

}

void SListPushBack(SListNode** ppHead, DataType x)//尾插
{
    assert(ppHead);

    SListNode* tmp = *ppHead;

    if (ppHead == NULL)
    {
        *ppHead = BuySListNode(x);
        return;
    }

    while (tmp->_next)
    {
        tmp = tmp->_next;
    }

    tmp->_next = BuySListNode(x);
}

void SListPopBack(SListNode** ppHead)//尾刪
{
    assert(ppHead);
    SListNode* tmp = *ppHead;

    if ((tmp->_next)==NULL)//無節點
    {
        return;
    }
    else//有節點
    {
        while (tmp->_next->_next)
        {
            tmp = tmp->_next;
        }
        //將最後一個元素銷燬置空
        free(tmp->_next);
        tmp->_next = NULL;
    }

}

void SListPushFront(SListNode** ppHead, DataType x)//頭插
{
    assert(ppHead);

    if ((*ppHead) == NULL)
    {
        *ppHead = BuySListNode(x);
        (*ppHead)->_next = NULL;
    }
    else
    {
        SListNode *tmp = BuySListNode(x);
        tmp->_next = (*ppHead)->_next;
        (*ppHead)->_next = tmp;
    }

}

void SListPopFront(SListNode** ppHead)//頭刪
{
    assert(ppHead);

    if ((*ppHead)->_next == NULL)
    {
        return;
    }
    else
    {
        SListNode *tmp = (*ppHead)->_next;
        (*ppHead)->_next = tmp->_next;
        free(tmp);
        tmp = NULL;
    }

}


SListNode* SListFind(SListNode* pHead, DataType x)//查找
{
    SListNode* tmp = pHead;

    while (tmp)
    {
        if (tmp->_data == x)
            return tmp; 
        else
            tmp = tmp->_next;
    }

    return NULL;
}

void SListInsert(SListNode** ppHead, SListNode* pos, DataType x)//pos前插入
{
    assert(ppHead && pos);

    SListNode *p = (*ppHead);
    SListNode *q = BuySListNode(x);

    while (p->_next != pos)
    {
        p = p->_next;
    }
    p->_next = q;
    q->_next = pos;
}

void SListErase(SListNode** ppHead, SListNode* pos)//pos位置刪除
{
    assert(ppHead && pos);

    SListNode* tmp = *ppHead;
    while (tmp->_next != pos)
    {
        tmp = tmp->_next;
    }
    tmp->_next = pos->_next;

    free(pos);
    pos = NULL;
}

void SListAt(SListNode** ppHead, SListNode *pos, DataType x)//替換
{
    assert(ppHead && pos);

    SListNode *tmp = *ppHead;

    while (tmp->_next != pos)
    {
        tmp = tmp->_next;
    }
    tmp->_next->_data = x;
}

Test.c(測試)

#include"SingleLinkedList.h"

void TestPushBack(SListNode *list)//尾插
{


    SListPushBack(&list, 1);
    SListPrint(list);

    SListPushBack(&list, 2);
    SListPrint(list);

    SListPushBack(&list, 3);
    SListPrint(list);

    SListDestory(&list);
}

void TestPopBack(SListNode *list)//尾刪
{
    SListNode*tmp = list;
    //先插入3個數字
    SListPushBack(&list, 1);
    SListPushBack(&list, 2);
    SListPushBack(&list, 3);
    SListPrint(list);

    list = tmp;
    //開始尾刪
    SListPopBack(&tmp);
    SListPrint(tmp);

    SListPopBack(&tmp);
    SListPrint(tmp);

    SListPopBack(&tmp);
    SListPrint(tmp);


    SListDestory(&list);
}

void TestPushFront(SListNode *list)//頭插
{


    SListPushFront(&list, 1);
    SListPrint(list);

    SListPushFront(&list, 2);
    SListPrint(list);

    SListPushFront(&list, 3);
    SListPrint(list);

    SListDestory(&list);
}

void TestPopFront(SListNode *list)//頭刪
{
    SListPushFront(&list, 1);
    SListPushFront(&list, 2);
    SListPushFront(&list, 3);
    SListPrint(list);

    SListPopFront(&list);
    SListPrint(list);//刪掉3剩下2和1
    SListPopFront(&list);
    SListPrint(list);//剩下1
    SListPopFront(&list);
    SListPrint(list);//空
    SListPopFront(&list);
    SListPrint(list);//空

    SListDestory(&list);
}


void TestInsert(SListNode *list)//pos前插入
{

    SListNode*pos = NULL;

    //尾插
    SListPushBack(&list, 7);
    SListPushBack(&list, 8);
    SListPushBack(&list, 9);
    //頭插
    SListPushFront(&list, 3);
    SListPushFront(&list, 2);
    SListPushFront(&list, 1);

    SListPrint(list);

    pos = SListFind(list,7);
    SListInsert(&list,pos, 6);
    SListPrint(list);

    pos = SListFind(list, 6);
    SListInsert(&list, pos, 5);
    SListPrint(list);

    pos = SListFind(list, 5);
    SListInsert(&list, pos, 4);
    SListPrint(list);

    /*pos = SListFind(list, 20);//因爲鏈表沒有20,pos爲空指針,在SListInsert函數的斷言會報錯
    SListInsert(&list, pos, 10);
    SListPrint(list);*/

    SListDestory(&list);
}


void TestErase(SListNode *list)//pos位置刪除
{
    SListNode*pos = NULL;

    //尾插
    SListPushBack(&list, 7);
    SListPushBack(&list, 8);
    SListPushBack(&list, 9);
    //頭插
    SListPushFront(&list, 3);
    SListPushFront(&list, 2);
    SListPushFront(&list, 1);

    SListPrint(list);

    pos = SListFind(list,1);
    SListErase(&list, pos);
    SListPrint(list);

    pos = SListFind(list, 2);
    SListErase(&list, pos);
    SListPrint(list);

    pos = SListFind(list, 3);
    SListErase(&list, pos);
    SListPrint(list);

    pos = SListFind(list, 7);
    SListErase(&list, pos);
    SListPrint(list);

    pos = SListFind(list, 8);
    SListErase(&list, pos);
    SListPrint(list);

    pos = SListFind(list, 9);
    SListErase(&list, pos);
    SListPrint(list);

    SListDestory(&list);
}


void TestFind(SListNode *list)//查找
{
    SListPushBack(&list, 1);
    SListPushBack(&list, 2);
    SListPushBack(&list, 3);

    //數據存在,打印該數據;查找不存在數據會發生異常
    printf("%d\n", SListFind(list, 3)->_data);
    printf("%d\n", SListFind(list, 2)->_data);
    printf("%d\n", SListFind(list, 1)->_data);
    //printf("%d\n", SListFind(list, 0)->_data);//鏈表內沒有數據data存放0,因此返回NULL,而用空指針訪問data數據會異常

    SListDestory(&list);
}



void TestAt(SListNode *list)//替換
{
    SListNode*pos = NULL;

    //頭插
    SListPushFront(&list, 3);
    SListPushFront(&list, 2);
    SListPushFront(&list, 0);

    //尾插
    SListPushBack(&list, 4);
    SListPushBack(&list, 8);
    SListPushBack(&list, 9);

    SListPrint(list);

    pos = SListFind(list, 0);
    SListAt(&list, pos, 1);
    SListPrint(list);

    pos = SListFind(list, 8);
    SListAt(&list, pos, 5);
    SListPrint(list);

    pos = SListFind(list, 9);
    SListAt(&list, pos, 6);
    SListPrint(list);

    SListDestory(&list);
}


int main()//想要測試哪個,則放開前面的雙斜線
{
    SListNode *list = pStructInit();

    //TestPushBack(list);//尾插
    //TestPopBack(list);//尾刪
    //TestPushFront(list);//頭插
    //TestPopFront(list);//頭刪
    //TestInsert(list);//pos前插入
    //TestErase(list);//pos位置刪除
    //TestFind(list);//查找
    //TestAt(list);//替換

    system("pause");
    return 0;
}

最後,那裏要是寫錯了,或者不懂的地方,歡迎評論或者私信給我,謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章