‘是瑶呀’数据结构之c语言实现单链表

如有问题欢迎指正

文章目录

前言

一、头文件SList.h

二、SList.c

1.动态申请一个结点

2.单链表打印

3.单链表尾插

4.单链表的头插

5.单链表的尾删

6.单链表头删

7.单链表查找

8.单链表在pos位置之后插入x

9.单链表删除pos位置之后的值 

总结



前言

顺序表缺点:头部中间插入数据需要移动数据,效率低下。空间不够需要扩容,扩容有一定消耗且可能会造成空间浪费。

链表:

概念:链表是一种 物理存储结构上非连续 、非顺序的存储结构,数据元素的 逻辑顺序 是通过链表
中的 指针链接 次序实现的 。链表有八种结构:
本文只有无头单项不循环

一、头文件SList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SListDataType;

typedef struct SListNode
{
	SListDataType data;
	struct SListNode* next;//存的是下一个节点的地址,下一个节点是结构体,所以指针类型是结构体
}SLN;

// 动态申请一个结点
SLN* BuySListNode(SListDataType x);
// 单链表打印
void SListPrint(SLN* plist);
// 单链表尾插
void SListPushBack(SLN** pplist, SListDataType x);
// 单链表的头插
void SListPushFront(SLN** pplist, SListDataType x);
// 单链表的尾删
void SListPopBack(SLN** pplist);
// 单链表头删
void SListPopFront(SLN** pplist);
// 单链表查找
SLN* SListFind(SLN* plist, SListDataType x);
// 单链表在pos位置之后插入x
void SListInsertAfter(SLN* pos, SListDataType x);
// 单链表删除pos位置之后的值
void SListEraseAfter(SLN* pos);

二、SList.c

1.动态申请一个结点

代码如下(示例):

#include"SList.h"
// 动态申请一个结点
SLN* BuySListNode(SListDataType x)
{
    SLN* tmp = (SLN*)malloc(sizeof(SLN));
    if (tmp == NULL)//检查malloc是否成功
    {
        perror("malloc faild");
        exit(-1);
    }
    tmp->data = x;
    tmp->next = NULL;     
    return tmp;
}

2.单链表打印

代码如下(示例):

void SListPrint(SLN* plist)
{
    SLN* cur = plist;
    while (cur != NULL)
    {
        printf("%d->", cur->data);
        cur = cur->next;
    }
    printf("NULL\n");
}

3.单链表尾插

void SListPushBack(SLN** pplist, SListDataType x)//因为传的是一个指针的地址,所以用二                                                                                      级指针接收
{
    assert(pplist);//判断是否需要断言,先假设可以为空看看合不合理,不合理说明不能为空                               需要断言
    SLN* newnode = BuySListNode(x);

//注意分情况讨论,不要忽视没有数据时的情况
    if (*pplist == NULL)
    {
        *pplist = newnode;
    }
    else
    {
        SLN* tail = *pplist;
        while (tail->next != NULL)
        {
            tail = tail->next;
        }
        tail->next = newnode;
    }

4.单链表的头插

void SListPushFront(SLN** pplist, SListDataType x)
{
    assert(pplist);

    SLN* newnode = BuySListNode(x);

//这里写完会发现没有数据时的处理方法和有数据时的一样所以不用分情况
    /*if (*pplist == NULL)
    {
        *pplist = newnode;
    }
    else
    {
        newnode->next = *pplist;
        *pplist = newnode;
    }*/

    newnode->next = *pplist;
    *pplist = newnode;
}

5.单链表的尾删

void SListPopBack(SLN** pplist)
{
    assert(pplist);
    assert(*pplist);//当plist为空时,删除则没有意义,所以不能为空
    if ((*pplist)->next == NULL)
    {
        free(*pplist);
        *pplist = NULL;
    }
    else
    {
        SLN* tail = *pplist;
        while (tail->next->next != NULL)
        {
            tail = tail->next;
        }
        free(tail->next);
        tail->next = NULL;
    }
}

//这里必须注意用malloc,realloc申请的空间,不用是必须free释放,否则会造成内存泄漏

6.单链表头删

void SListPopFront(SLN** pplist)
{
    assert(pplist);
    assert(*pplist);
    SLN* phead = *pplist;
    *pplist = (*pplist)->next;
    free(phead);
    phead = NULL;

}

7.单链表查找

SLN* SListFind(SLN* plist, SListDataType x)
{
    SLN* tail = plist;
    while (tail != NULL)
    {
        if (tail->data == x)
        {
            return tail;
        }
        tail = tail->next;
    }
    return NULL;
}

8.单链表在pos位置之后插入x

void SListInsertAfter(SLN* pos, SListDataType x)
{
    assert(pos);//pos不能为空,否则没有意义
    SLN* newnode = BuySListNode(x);
    SLN* next = pos->next;
    pos->next = newnode;
    newnode->next = next;
}

9.单链表删除pos位置之后的值 

void SListEraseAfter(SLN* pos)
{
    assert(pos);
    assert(pos->next);//如果为空则不需要删除,属于多此一举,既然调用此函数就是想实现                                          删除,所以pos->next不能为空
    SLN* next = pos->next;
    pos->next = next->next;
    free(next);
    next = NULL;
}


总结

无头单向非循环链表: 结构简单 ,一般不会单独用来存数据。实际中更多是作为 其他数据结
构的子结构 ,如哈希桶、图的邻接表等等。另外这种结构在 笔试面试 中出现很多。
使用malloc和realloc函数申请的空间,不用时一定要用free函数释放
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值