C语言实现-数据结构-单链表

1.链表的简介

链表中的数据是以结点来表示的。

每个结点的构成元素(数据元素的映象) + 指针(指示后继元素存储位置)。

  • 元素 就是存储数据的存储单元,
  • 指针 就是连接每个结点的地址数据。

2.链表结构体的创建

typedef int DataType;//用typedef定义int类型的别名叫DataType

typedef struct SListNode {
    DataType data; // 值 
    struct SListNode *pNext; // 指向下一个结点 
} SListNode;

3.链表的初始化

// 初始化 
void SListInit(SListNode **ppFirst)
{
    //初始化则把头节点置空即可,申请空间会在需要时写出
    *ppFirst = NULL;
}

4. 动态申请节点

static SListNode * BuyNewNode(DataType data)
{
    SListNode *pNewNode = (SListNode *)malloc(sizeof(SListNode));
    assert(pNewNode);
    pNewNode->data = data;
    pNewNode->pNext = NULL;
    return pNewNode;
}

5.头部插入

void SListPushFront(SListNode **ppFirst, DataType data)
{
    SListNode *newNode = BuyNewNode(data);//插入前肯定要买一个节点了
    newNode->pNext = *ppFirst;
    *ppFirst = newNode;
}

6.尾部插入

void SListPushBack(SListNode** ppFirst, DataType data)
{
    //尾插肯定要买一个节点
    SListNode *newNode = BuyNewNode(data);
    //如果链表是空的,就把新节点给*ppfirst
    if (*ppFirst == NULL)
    {
        *ppFirst = newNode;
        return;
    }

    SListNode *pNode = *ppFirst;
    for (pNode; pNode->pNext != NULL; pNode = pNode->pNext)
    {
        ;
    }
    //到这里,找到了最后一个节点
    newNode->pNext = pNode->pNext;//将新节点的next指向原来pnode的next,(即null)
    pNode->pNext = newNode;//然后让原来节点的next指向新节点
}

7.头部删除

void SListPopFront(SListNode **ppFirst)
{
    if (*ppFirst == NULL)
    {
        printf("链表是空的");
        return;
    }
    //把第一个节点phead初始化设置好
    SListNode *pHead = *ppFirst;
    //*pnext是第二个节点
    SListNode *pNext = pHead->pNext;
    //释放头节点
    free(pHead);
    //将第二个节点置成ppfirst(头节点)
    *ppFirst = pNext;
}

8.尾部删除

void SListPopBack(SListNode **ppFirst)
{
    //排除链表为空的情况
    if (*ppFirst == NULL)
    {
        printf("链表为空\n");
        return;
    }
    //如果链表里就只有一个元素,直接删除
    if ((*ppFirst)->pNext == NULL)
    {
        free(*ppFirst);
        *ppFirst = NULL;
    }

    SListNode *pNode, *pNext;
    pNode = *ppFirst;
    //找到倒数第二个元素,
    while (pNode->pNext->pNext != NULL)
    {
        pNode = pNode->pNext;
    }

    pNext = pNode->pNext;//设置为pnode的下一个节点为pnext(即找到最后一个节点)
    pNode->pNext = pNext->pNext;//把pnode的next直接指向null
    free(pNext);//释放最后一个节点
}

9. 在指定的结点前插入

void SListInsert(SListNode **ppFirst, SListNode *pPos, DataType data)
{
    //如果链表是空的,则可以直接头插
    if (*ppFirst == NULL && pPos == NULL)
    {
        SListPushFront(ppFirst, data);
        return;
    }
    SListNode *pNode;
    //找到ppos
    for (pNode = *ppFirst; pNode->pNext != pPos; pNode = pNode->pNext)
    {
        ;
    }
    //买一个节点
    SListNode* pNewNode = BuyNewNode(data);
    //将新节点的pnext指向ppos
    pNewNode->pNext = pPos;
    //将ppos的前一个节点pnode 的 pnext 指向新节点
    pNode->pNext = pNewNode;
}

10. 给定节点删除

void SListErase(SListNode **ppFirst, SListNode *pPos)
{
    //如果给定的节点就是当前第一个节点,直接头删
    if (*ppFirst == pPos)
    {
        SListPopFront(ppFirst);
        return;
    }
    SListNode* pNode;
    //找到ppos
    for (pNode = *ppFirst; pNode->pNext != pPos; pNode = pNode->pNext)
    {
        ;
    }
    //pnode是ppos的前一个节点
    //将pnode的next指向ppos的下一个节点
    pNode->pNext = pPos->pNext;
    //释放ppos即可
    free(pPos);
}

11. 按值查找,返回第一个找到的结点指针,如果没找到,返回 NULL

SListNode* SListFind(SListNode *pFirst, DataType data)
{
    SListNode* pNode;
    pNode = pFirst;
    while (pNode != NULL)
    {
        if (pNode->data == data)
        {
            printf("找到了%d\n",pNode->data);
            return pNode;
        }
        pNode = pNode->pNext;
    }
    printf("链表中没有此值:%d\n",data);
    return NULL;
}

12. 按值删除,只删遇到的第一个

void SListRemove(SListNode **ppFirst, DataType data)
{
    if (*ppFirst == NULL)
    {
        printf("链表为空\n");
        return;
    }
    //按值删除的话,肯定要先按值找到哪个节点,slistfind返回的是那个节点的地址
    SListNode* res = SListFind(*ppFirst, data);
    //如果找到了那第一个符合的节点,就删除给定节点
    if (res != NULL)
    {
        printf("开始删除\n", data);
        SListErase(ppFirst, res);//按给定节点进行删除
        return;
    }

    printf("链表中没有这个值\n");
}

13.按值删除,删除所有的

void SListRemoveAll(SListNode **ppFirst, DataType data)
{
    if (*ppFirst == NULL)
    {
        printf("链表为空\n");
        return;
    }
    SListNode* pNode = *ppFirst;
    SListNode* pDel;//这里要保存删除节点的信息,防止直接删除后信息丢失
    printf("开始删除链表中所有此值:%d\n", data);
    while (pNode->pNext != NULL)//按值删除,遍历链表里所有的节点
    {
        //删除时,不能直接定位到目标节点,否则会丢失信息,应该要先保存起来
        if (pNode->pNext->data == data)
        {
            pDel =  pNode->pNext;
            pNode->pNext = pDel->pNext;
            free(pDel);
        }
        else
        {
            pNode = pNode->pNext;
        }
        //别忘记考虑第一个节点
        if ((*ppFirst)->data == data)
        {
            //如果是第一个节点,那就直接头删掉即可
            SListPopFront(ppFirst);
        }
    }
}

14.链表的销毁

void SListDestroy(SListNode **ppFirst)
{
    SListNode *pNode, *pNext;
    for (pNode = *ppFirst; pNode != NULL; pNode = pNext)
    {
        pNext = pNode->pNext;
        free(pNode);
    }
    *ppFirst = NULL;
}

15.打印链表

void Print(SListNode *pHead)
{
    SListNode *pNode;
    for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
    {
        printf("%2d-> ", pNode->data);
    }
    printf("NULL\n");
}

测试代码

void test()
{
    SListNode *SList;
    SListInit(&SList);
    SListPushBack(&SList, 3);
    SListPushFront(&SList, 1);
    SListPushBack(&SList, 3);
    SListPushFront(&SList, 2);
    SListPushFront(&SList, 3);
    SListPushBack(&SList, 3);
    SListPushBack(&SList, 3);
    SListPushBack(&SList, 4);
    SListPushBack(&SList, 3);
    Print(SList);
    //SListPopBack(&SList);
    //SListPopFront(&SList);
    SListFind(SList, 5);
    SListRemove(&SList, 2);
    SListRemoveAll(&SList, 3);
    Print(SList);
}

主函数

#define  _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include"lb.h"

int main()
{
    test();
    system("pause");
    return 0;
}

运行结果

C语言实现-数据结构-单链表_第1张图片

你可能感兴趣的:(C)