链表之单链表

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

前言

讲解单链表的使用,用C语言实现。


一、链表是什么?

1.链表定义:链表是一种数据结构,在物理存储结构上是非连续的,在逻辑结构上通过指针链接实现连续性。链表和顺序表相比,具有按需申请释放空间和不需要挪动数据的优点。

2.链表基本结构

typedef int SLTdatatype;

typedef struct SLTnode
{
    SLTdatatype value;         //数据
    struct SLTnode* next;    //结构体指针,指向下一个结构体或null
}SLTnode;

链表就是由这样一个个结构体链接而成的。

二、链表基本操作

1.结点创建

SLTnode* BuySLTnode(SLTDatatype x)
{
    SLTnode* newnode=(SLTnode*)malloc(sizeof(SLTnode));
    if(newnode==NULL)
    {
    perror("malloc fail\n");
    exit(-1);
    }
    else
    newnode->data=x;
    newnode->next=NULL;
    return newnode;
}
 

该函数负责创建结点,返回一个指向结点的指针。

2.创建简单链表

代码如下:


SLTnode* CreatListnode(int n)
{    SLTnode* phead=NULL,*ptail=NULL;

     for(int i=0;i<10;i++)
    {
    SLTnode* newnode=BuySLTnode(i);     //创建结点
    if(phead==NULL)
    {
    phead=ptail=newnode;      //第一个结点
    }
    else
    {
    ptail->next=newnode;
    ptail=newnode;
    }
    return phead;
}

顺序表最重要的是结构,而链表最重要的就是头,所以在创建链表的时候要保护好头,即第一个结点,可以看到,代码没有直接对头进行操作,这样可以避免内存泄漏。

3.读链表

代码如下:

void PrintListnode(SLTnode* phead)
{
    while(phead!=Null)
    {
    SLTnode* cur=phead;    //没有直接对phead操作
    printf("%d->"cur->data);
    cur=cur->next;
    }
    printf("Null\n");
}
    
    

4.单链表尾插尾删



void PushBack(SLTnode** pphead,SLTDatatype x)   
{
    STLnode* newnode=BuySTLnode(x);
    if(*pphead==NULL)                 //链表为空
    {*pphead=newnode;}

    else
    tail=*pphead;                //链表不为空
    while(tail->next)
    {
    tail=tail->next;
    }
    tail->next=newnode;
}  


void popBack(SLTnode** pphead)
{
    assert(*pphead);
    SLTnode* tail=*pphead;
    if(tail->next==NULL)
    {free(tail);
    tail=NULL;}
    while(tail->next->next)
    {
    tail=tail->next;
    }
    free(tail->next);
    tail->next=NULL;
}

易错点:这里要用到二级指针,因为当链表为空时,需要改变头指针,所以要传指针的地址,形参用二级指针,也可以不传二级指针,函数用返回值。当链表不为空,改变的是结构体,只要用结构体指针就可以了。


5.单链表头插头删

void pushfront(SLTnode** pphead,SLTdatatype x)    //同样用到了二级指针
{
    SLTnode* newnode=BuySLTnode(x);
    newnode->next=*pphead;
    *pphead=newnode;
}


void popfront(SLTnode** pphead)
{
    assert(*pphead);
    SLTnode* next=(*pphead)->next;
    free(*pphead);
    *pphead=next;
}

相比尾插尾删,单链表用头插头删更加简单,不用考虑链表是否为空。

6.指定位置的插入

void SLTInsertAfter(SLTnode* pos,SLTdatatype x)     //在pos位置后面插入
{
    assert(pos);
    SLTnode* newnode=BUYnode(x);
    newnode->next=pos->next;
    pos->next=newnode;
}

void SLTInsert(SLTnode** pphead,SLTnode* pos,SLTdatatype x)  //在pos位置前面插入
{
    assert(pos);
    if(pos==*pphead)
    {
    pushfront(pphead,x);
    }
    else
    {
    SLTnode*prev=*pphead;
    while(prev->next!=pos)
    {prev=prev->next;}
    SLTnode*newnode=BUYnode(x);
    prev->next=newnode;
    newnode->next=pos;
    }
}
    

7.指定位置的删除

void SLTEraseAfter(SLTnode** pphead,SLTnode* pos)  //删除pos位置后面
 {   assert(pos);
    if (pos->next == NULL)
    {
        return;
    }
    SListNode* next = pos->next;
    pos->next = next->next;
    free(next);
}


void SLTErase(SLTnode** pphead,STLnode* pos)
{
   assert(pos);
    if (*pphead == pos)
    {
        SListPopFront(pphead);
    }
    else
    {
        SListNode* pre = *pphead;
        while (pre->next != pos)
        {
            pre = pre->next;
        }
        pre->next = pos ->next;
        free(pos);
    }

8.链表查找

SLTnode* SLTFind(SLTnode*phead,SLTdatatype x)
{
    
    SLTNode* cur = phead;
    while (cur)
    {
        if (cur->data == x)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

9.链表销毁

void SLTDestory(SLTnode** pphead)
{
    SLTNode* cur = *pphead;
    while (cur)
    {
        SLTNode* next = cur->next;
        free(cur);
        cur = next;
    }
    free(*pphead);
    *pphead = NULL;
}

10.完整代码

头文件

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLTDateType;
typedef struct SListNode
{
	SLTDateType data;
	struct SListNode* next;
}SListNode;

// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x);
SListNode* Createlist(SLTDateType x);


// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 单链表在pos位置之后插入x
SListNode* SListFind(SListNode* plist, SLTDateType x);
//在pos位置之前插入x
void SListInsertAfter(SListNode* pos, SLTDateType x);
void SListInsert(SListNode** pphead,SListNode* pos, SLTDateType x);


// 单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos);
//删除pos地址的节点
void SListErase(SListNode** pphead,SListNode* pos);

// 单链表的销毁
void SListDestroy(SListNode* *plist);

函数实现

#include"slist.h"


SListNode* BuySListNode(SLTDateType x)
{
    SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
    if (newnode==NULL)
    {
        perror("malloc fail");
        exit(-1);
    }
    newnode->data = x;
    newnode->next = NULL;
    return newnode;
}
           
SListNode* Createlist(SLTDateType x)
{
    SListNode* phead=NULL,*ptail = NULL;
    
    for (int i = 0; i < x; i++)
    {
        SListNode* newnode = BuySListNode(i);
        if (phead == NULL)
        {
            ptail = phead = newnode;
        }
        else
        {
            ptail->next = newnode;
            ptail = newnode;
        }
    }
    return phead;
}

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


void SListPushBack(SListNode** pplist, SLTDateType x)      //尾插
{
    SListNode* newnode = BuySListNode(x);
    if (*pplist == NULL)
    {
        *pplist = newnode;
    }

    else
    {
        SListNode* tail = *pplist;
        while (tail->next)
        {
            tail = tail->next;
        }
        tail->next = newnode;
    }
}


void SListPopBack(SListNode** pplist)         //尾删
{
    assert(*pplist);

    if ((*pplist)->next==NULL)
    {
        free(*pplist);
        *pplist = NULL;
    }
    else
    {
        SListNode* newnode = *pplist;
        while (newnode->next->next)
        {
            newnode = newnode->next;
        }
        free(newnode->next);
        newnode->next = NULL;

    }
}



void SListPushFront(SListNode** pplist, SLTDateType x)       //头插
{
    SListNode* newnode = BuySListNode(x);
    newnode->next = *pplist;
    *pplist = newnode;
}


void SListPopFront(SListNode** pplist)     //头删
{
    assert(*pplist);
    SListNode* newnode = ((*pplist)->next);
    free(*pplist);
    *pplist = newnode;
}


SListNode* SListFind(SListNode* plist, SLTDateType x)    //单链表查找
{
    SListNode* cur = plist;
    while (cur)
    {
        if (cur->data == x)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}


void SListInsertAfter(SListNode* pos, SLTDateType x)       //在pos位置后面插入
{
    assert(pos);
    SListNode* newnode = BuySListNode(x);
    newnode->next = pos->next;
    pos->next = newnode;
}

void SListInsert(SListNode**pphead,SListNode*pos,SLTDateType x)  //在pos位置前面插入x
{
    assert(pos);
    if (*pphead == pos)
    {
        SListPushFront(pphead, x);
    }
    else
    {
        SListNode* newnode = BuySListNode(x);
        SListNode* pre = *pphead;
        while (pre->next != pos)
        {
            pre = pre->next;
        }
        pre->next = newnode;
        newnode->next = pos;
    }
}


void SListEraseAfter(SListNode* pos)        //在pos位置后面删除
{
    assert(pos);
    if (pos->next == NULL)
    {
        return;
    }
    SListNode* next = pos->next;
    pos->next = next->next;
    free(next);
}


void SListErase(SListNode**pphead,SListNode* pos)  //在pos位置删除
{
    assert(pos);
    if (*pphead == pos)
    {
        SListPopFront(pphead);
    }
    else
    {
        SListNode* pre = *pphead;
        while (pre->next != pos)
        {
            pre = pre->next;
        }
        pre->next = pos ->next;
        free(pos);
    }
}




void SListDestroy(SListNode** plist)          //链表销毁
{

    SListNode* cur = *plist;
    while (cur)
    {
        SListNode* next = cur->next;
        free(cur);
        cur = next;
    }
    free(*plist);
    *plist = NULL;

}

总结

萌新blog,很多地方还有不足,此博客更多的是记录自己学习的过程。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ke vin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值