单链表基本操作——头插头删、尾插尾删、任意位置增加删除节点、查找元素、打印、销毁

单链表基本操作——头插头删、尾插尾删、任意位置增加删除节点、查找元素、打印、销毁_第1张图片

#pragma once
#include
#include
#include

typedef int DataType;

typedef struct SlistNode{
    DataType data;
    struct SlistNode *pNext;
}Slist, *PNode;

////////////////////////////////////////////////////////////////////
//////////////////声明函数


void SListInit(PNode* pHead);// 初始化单链表 

PNode BuySListNode(DataType data);// 创建结点 

void SListPushBack(PNode* ppHead, DataType data);// 尾插 

void SListPopBack(PNode* ppHead);// 尾删 

void SListPushFront(PNode* ppHead, DataType data);// 头插 

void SListPopFront(PNode* ppHead);//头删

// 在链表中查找元素data,返回该结点在链表中的位置 
PNode Find(PNode pHead, DataType data);

void SListInsert(PNode* ppHead, PNode pos, DataType data);// data插入在pos之前 

void SListErase(PNode* ppHead, PNode pos);// 删除链表中pos位置的结点 

size_t SlistSize(PNode pHead);// 获取链表中结点的个数 

// 判断链表是否为空,若为空,返回true,否则返回false 
size_t Empty(PNode pHead);

void SListDestroy(PNode* ppHead);// 销毁单链表 

void SListPrint(PNode pHead); // 打印单链表



//////////////////////////////////////////////////////////
//////////函数定义



void SListInit(PNode* pHead)//初始化
{
    assert(pHead);
    *pHead = NULL;
}

PNode BuySListNode(DataType data)// 创建结点 
{
    PNode pNewNode = (PNode)malloc(sizeof(Slist));
    assert(pNewNode);

    pNewNode->pNext = NULL;
    pNewNode->data = data;
    return pNewNode;
}

void SListPushBack(PNode* ppHead, DataType data)// 尾插
{
    PNode pNewNode = BuySListNode(data);
    assert(ppHead);

    if (*ppHead == NULL)//ppHead为指向存有头结点地址的二级指针
        *ppHead = pNewNode;//让指向头结点的指针指向新构建的节点
    else{
        PNode pTailNode = *ppHead;
        while (pTailNode->pNext){//尾结点的Next不为空则向前走
            pTailNode = pTailNode->pNext;
        }
        pTailNode->pNext = pNewNode;
    }

}

void SListPrint(PNode pHead) // 打印单链表
{
    PNode pCur = pHead;
    while (pCur)
    {
        printf("%d->", pCur->data);
        pCur = pCur->pNext;
    }
    printf("NULL\n");
}



void SListPopBack(PNode* ppHead)// 尾删 
{
    if (*ppHead == NULL){
        printf("链表已空\n");
        return;
    }
    else if (((*ppHead)->pNext) == NULL){
        free(*ppHead);
        *ppHead = NULL;
    }
    else{
        PNode pCur = *ppHead;
        PNode pNewTailNode = NULL;
        while (pCur->pNext){
            pNewTailNode = pCur;//标记下尾结点的前一个节点位置
            pCur = pCur->pNext;//找到尾结点
        }
        free(pCur->pNext);//释放掉尾结点
        pNewTailNode->pNext = NULL;
    }
}

void SListPushFront(PNode* ppHead, DataType data)// 头插 
{
    PNode NewSlistNow = BuySListNode(data);// 创建结点 
    NewSlistNow->pNext = *ppHead;
    *ppHead = NewSlistNow;
}

void SListPopFront(PNode* ppHead)//头删
{
    assert(ppHead);
    PNode pDelNode = NULL;
    if ((*ppHead) == NULL){
        printf("链表已空\n");
        return;
    }

    pDelNode = *ppHead;    //将头结点标记起来
    *ppHead =pDelNode->pNext ;//把指向头结点的指针指向第二个节点
    free(pDelNode);//释放头节点
}

// 在链表中查找元素data,返回该结点在链表中的位置 
PNode Find(PNode pHead, DataType data)
{
    PNode pCur = pHead;
    while (pCur){
        if (data == pCur->data)
            return pCur;
        else
            pCur = pCur->pNext;      //从头到尾遍历
    }

    return NULL;
}

void SListInsert(PNode* ppHead, PNode pos, DataType data)// data插入在pos节点之前 
{
    assert(ppHead);
    if (*ppHead == NULL || pos == NULL)//没有结点或pos位置为空
        return;
    else {
        PNode pNewNode = BuySListNode(data);
            //if ((*ppHead)->pNext == NULL){//此处在链表有多节点,要插入的节点是头结点的场景下出错
            //pNewNode->pNext = *ppHead;
            //pNewNode = *ppHead;
        if (pos==*ppHead){
            pNewNode->pNext = *ppHead;
            *ppHead = pNewNode;
        }
        else{
            PNode pPrePosNode = *ppHead;
            while ( pPrePosNode->pNext != pos){//找到pos节点的前一个节点,标记为pPrePosNode
                pPrePosNode = pPrePosNode->pNext;
            }
            if (pPrePosNode){
                pPrePosNode->pNext = pNewNode;
                pNewNode->pNext = pos;        //将要插入节点的next指向pos节点
            }
        }
    }

}


void SListErase(PNode* ppHead, PNode pos)// 删除链表中pos位置的结点 
{
    assert(ppHead);
    if (*ppHead == NULL || pos == NULL)
        return;
    else if (pos == *ppHead){
        *ppHead = pos->pNext;
        free(pos);
    }

    else{
        PNode pPrePosNode = *ppHead;
        while (pPrePosNode->pNext != pos)//找到pos节点的前一个节点,标记为pPrePosNode
            pPrePosNode = pPrePosNode->pNext;   
        pPrePosNode->pNext = pos->pNext;
        free(pos);
    }
}

size_t SlistSize(PNode pHead)//返回链表中节点个数
{
    size_t count = 0;
    PNode pCur = pHead;
    while (pCur){
        ++count;
        pCur = pCur->pNext;
    }
    return count;
}

size_t Empty(PNode pHead)//判空
{
    return pHead == NULL;

}

void SListDestroy(PNode* ppHead)// 销毁单链表 
{
    PNode pCur = NULL;
    PNode pPreCur = NULL;
    if (*ppHead == NULL)
        return;


    //正向销毁
    while (pCur){
        pPreCur = pCur;
        pCur = pCur->pNext;
        free(pPreCur);
    }
    *ppHead = NULL;
/*
     逆向销毁

    while(*ppHead){
        pCur = (*ppHead);
        while(pCur->pNext){
            pPreCur = pCur;
            pCur = pCur->pNext;
    }
    free(pCur);
    pPreCur->pNext = NULL;
}
*ppHead = NULL;
*/

}





/////////////////////////////////////////////////////////////
///////////////////////////////测试
void test1()
{
    PNode pHead;
    PNode pos;

    SListInit(&pHead);//初始化

    printf("尾插\n");//尾插
    SListPushBack(&pHead, 1);
    SListPushBack(&pHead, 2);
    SListPushBack(&pHead, 3);
    SListPushBack(&pHead, 5);
    SListPushBack(&pHead, 6);
    SListPushBack(&pHead, 7);
    SListPushBack(&pHead, 8);
    SListPrint(pHead); // 打印单链表

    printf("尾删\n");
    SListPopBack(&pHead);
    SListPopBack(&pHead);
    SListPrint(pHead); // 打印单链表

    printf("头插\n");
    SListPushFront(&pHead, 0);
    SListPrint(pHead); // 打印单链表

    printf("头删\n");
    SListPopFront(&pHead);
    SListPrint(pHead); // 打印单链表

    printf("查找元素\n");
    PNode pSearchNode = Find(pHead, 4);
    if (pSearchNode)
        printf("链表中存在此元素\n");
    else
        printf("链表中不存在此元素\n");

    pos = Find(pHead, 1);
    printf("在pos节点前插入\n");
    SListInsert(&pHead, pos, 0);
    pos = Find(pHead, 5);
    SListInsert(&pHead, pos, 4);
    SListPrint(pHead); // 打印单链表

    pos = Find(pHead, 1);
    SListErase(&pHead, pos);
    SListPrint(pHead); // 打印单链表

    size_t size = SlistSize(pHead);
    printf("链表节点个数为->%d\n", size);

    SListDestroy(&pHead);//销毁链表
}

尾插:
先分析情况
1、头结点为空——>直接让头结点指向要插入的节点
2、多个节点——>
1)找到最后一个节点
2)最后一个节点的next指向新节点
3)新节点的next指向空

尾删:
分析情况
1、头结点为空:返回
2、只有头结点:释放头结点 头结点指向空
3、有多个节点:1)找倒尾结点和尾结点的前一个节点,标记下来
2)删掉尾结点,尾结点前一个节点指向空

头插:
分析情况
1、空 :头结点指针直接指向新节点
2、有节点:新节点的next指向头结点,把头结点指针指向新节点

data插入在pos节点之前 :
分析情况:
1、为空:返回
2、pos为头结点:头插
3、多个节点:先找到 pos 节点的位置,标记 pos 前一个节点为pre

你可能感兴趣的