单链表的C语言实现

在学习数据结构中,紧接着顺序表接触的就是单链表,那么单链表是什么呢?
1.什么是单链表?
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。

2.结构?
链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。以“结点的序列”表示线性表称作线性链表(单链表)。单链表是链式存取的结构,为找第 i 个数据元素,必须先找到第 i-1 个数据元素。

把单链表的特征说清楚后,我们就开始实现单链表的功能了。最基础的功能是实现它的增加、删除、查找等,因为它的线性特征,在增加的时候会存在头插、尾插,同样删除也一样。

SListNode.h

#define _CRT_SECURE_NO_WARNINGS 1

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

typedef int DataType;

typedef struct SListNode
{
    DataType data;
    struct SListNode* next;
}SListNode;

void InitSList(SListNode*& pHead);   //初始化
SListNode* BuyNode(DataType data);   //开辟空间
void Print(SListNode*& pHead);   //打印
void Destory(SListNode*& pHead);   //销毁

void PushBack(SListNode*& pHead, DataType data);   //尾插
void PopBack(SListNode*& pHead);    //尾删

void PushFront(SListNode*& pHead, DataType data);   //头插
void PopFront(SListNode*& pHead);    //头删

void Insert(SListNode*& pos,DataType data);//在某个位置插入某个数据
void Erase(SListNode*& pHead,SListNode* pos);//删除某个节点的数据
void Remove(SListNode*& pHead,DataType data); //删除某个数据所在的节点
SListNode* Find(SListNode*& pHead,DataType data); //查找某个数据所在的位置
SListNode.c

#include"SListNode.h"

void InitSList(SListNode*& pHead)   //初始化
{
    pHead = NULL;
}

SListNode* BuyNode(DataType data)   //开辟空间
{
    SListNode* node = (SListNode*)malloc(sizeof(SListNode));
    assert(node);
    node->data = data;
    node->next = NULL;
    return node;
}

void Print(SListNode*& pHead)   //打印
{
    SListNode* cur = pHead;
    if (cur == NULL)
        printf("null\n");
    while (cur)
    {
        printf("%d  ", cur->data);
        cur = cur->next;
    }
    printf("\n");
}

void PushBack(SListNode*& pHead, DataType data)   //尾插
{
    if (pHead == NULL)
        pHead = BuyNode(data);
    else
    {
        SListNode* cur = pHead;
        while (cur->next)
        {
            cur = cur->next;
        }
        cur->next = BuyNode(data);
    }
}

void PopBack(SListNode*& pHead)   //尾删
{
    assert(pHead);
    if (pHead->next == NULL)
    {
        free(pHead);
        pHead = NULL;
    }

    else
    {
        SListNode* cur = pHead;
        SListNode* pcur = cur;
        while(cur->next)
        {
            pcur = cur;
            cur = cur->next;
        }
        free(cur);
        cur = NULL;
        pcur->next = NULL;
    }


}

void PushFront(SListNode*& pHead, DataType data)   //头插
{
    if (pHead == NULL)
        pHead=BuyNode(data);
    else
    {
        SListNode* newHead = BuyNode(data);
        newHead->next = pHead;
        pHead = newHead;
    }
}

void PopFront(SListNode*& pHead)    //头删
{
    if (pHead == NULL)   //pHead为空
        return;
    else if (pHead->next == NULL)    //pHead->next为空
    {
        free(pHead);
        pHead = NULL;
    }
    else     //正常的删除
    {
        SListNode* cur = pHead;
        pHead = pHead->next;
        free(cur);
    }
}

void Insert(SListNode*& pos, DataType data)   //在某个位置插入某个数据
{
    if (NULL == pos)
        return;
    SListNode* newNode = BuyNode(data);
    newNode->next = pos->next;
    pos->next = newNode;
}

void Erase(SListNode*& pHead, SListNode* pos) //删除某个节点的数据
{
    assert(pHead&&pos);
    if (pos == pHead)
    {
        SListNode* tmp = pHead;
        pHead = pHead->next;
        free(tmp);
        tmp = NULL;
    }
    else
    {
        SListNode* cur = pHead;
        while (cur->next != pos)
        {
            cur = cur->next;
        }
        cur->next = pos->next;
        free(pos);
        pos = NULL;
    }
}

void Remove(SListNode*& pHead, DataType data)  //删除某个数据所在的节点
{
    assert(pHead);
    SListNode* pos = Find(pHead, data);
    if (pos == pHead)
    {
        SListNode* tmp = pHead;
        pHead = pHead->next;
        free(tmp);
        tmp = NULL;
    }

    else
    {
        SListNode* cur = pHead;
        while (cur->next!=pos)
        {
            cur = cur->next;
        }
        cur->next = pos->next;
        free(pos);
        pos = NULL;
    }

}

SListNode* Find(SListNode*& pHead, DataType data) //查找某个数据所在的位置
{
    SListNode* cur = pHead;
    assert(pHead);
    while(cur)
    {
        if(cur->data == data)
            return cur;
        cur = cur->next;
    }
    return NULL;
}

void Destory(SListNode*& pHead)   //销毁
{
    assert(pHead);
    free(pHead);
    pHead = NULL;
}

测试函数
#include"SListNode.h"

void Test1()   //尾插尾删
{
    SListNode* Slistnode;
    InitSList(Slistnode);
    PushBack(Slistnode, 1);
    PushBack(Slistnode, 2); 
    PushBack(Slistnode, 3);
    PushBack(Slistnode, 4);
    PushBack(Slistnode, 5);
    Print(Slistnode);

    PopBack(Slistnode);
    PopBack(Slistnode);
    PopBack(Slistnode);
    PopBack(Slistnode);
    Print(Slistnode);
}

void Test2()   //头插头删
{
    SListNode* Slistnode;
    InitSList(Slistnode);
    PushFront(Slistnode, 1);
    PushFront(Slistnode, 2);
    PushFront(Slistnode, 3);
    PushFront(Slistnode, 4);
    PushFront(Slistnode, 5);
    Print(Slistnode);

    PopFront(Slistnode);
    PopFront(Slistnode);
    PopFront(Slistnode);
    PopFront(Slistnode);
    Print(Slistnode);
}

void Test3()   //任意位置的插入删除
{
    SListNode* Slistnode;
    InitSList(Slistnode);
    PushFront(Slistnode, 1);
    PushFront(Slistnode, 2);
    PushFront(Slistnode, 3);
    PushFront(Slistnode, 4);
    PushFront(Slistnode, 5);
    Print(Slistnode);

    SListNode* pos1 = Find(Slistnode, 3);
    Insert(pos1, 7);
    Print(Slistnode);

    SListNode* pos2 = Find(Slistnode, 4);
    Erase(Slistnode, pos2);
    Print(Slistnode);

    Remove(Slistnode, 1);
    Print(Slistnode);

    Destory(Slistnode);
    Print(Slistnode);
}

int main()
{
    Test1();
    Test2();
    Test3();
    system("pause");
}

总结:整体代码部分如上,在这里需要注意几点:
1.对链表进行插入删除时,一定要分析可能出现的情况,比如头插时可能三种情况,当链表为空;当链表指向的下一个为空;正常的头插。只有将情况分析清楚,你才能按照逻辑去写代码。

2.在实现链表的时候,代码都差不多,但很多细节需要我们去注意。该断言的时候可以用assert,不需要的部分进行判断即可。

3.在测试较多的功能时,可以分步分模块测试,哪里有问题也比较好调试。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值