数据结构之单链表

线性链表


一、什么是线性链表?

线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元既可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素ai与其直接后继数据元素ai+1之间的逻辑关系,对数据ai来说,除了存储其本身的信息之外,还需要存储一个指示其直接后继的信息。这两部分构成数据ai的存储映像,称为结点。它包括两个域:数据域和指针域。指针域中存储的信息叫做指针或链,n个结点链构成一个链表,即为线性表的链式存储结构,又由于此链表的每个结点中只包含一个指针域,故称之为单链表。

二、单链表基本功能的实现

1.创建结构体以及初始化单链表(不带头结点)

//定义链表结点
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;


2.初始化单链表
//初始化链表
void InitSList(SListNode **pList)
{
    //assert(pList);
    *pList = NULL;
}

2.单链表的插入和删除操作

假设我们要在线性表的两个数据元素a和b之间插入一个数据元素x,已知p为其单链表存储结构中指向结点a的指针,为了插入数据元素x,首先要生成一个数据域为x的结点,然后插入在单链表中。根据插入操作的逻辑定义,还需要修改结点a中的指针域,令其指向结点x,而结点x中的指针域应该指向b,从而实现3个元素a、b、x之间逻辑关系的变化。假设s为指向结点x的指针,则上述指针修改用语句描述即为:
s ->next = p - >next; p ->next = s;

反之如果要在a、b、c之间删除b结点的话,仅需要修改a中的指针域即可。假设p为指向结点a的指针,则修改指针的语句为:
p ->next = p ->next ->next;

可见,在已知链表中元素插入或者删除的确切位置的情况下,在单链表中插入或者删除一个结点时,仅需要修改指针的指向而不需要移动元素。算法实现如下:

//尾部插入
void SListPush_Back(SListNode **plist,SLTDateType x)
{
    //assert(plist);
    SListNode *s = BuySListNode(x);
    SListNode *p = *plist;
    assert(s != NULL);
    //如果链表为空
    if (*plist == NULL)
    {
        *plist = s;
    } else{
        //链表不为空
        while (p ->next != NULL)
        {
            p = p ->next;
        }
        p ->next = s;
    }
}

//尾部删除
void SListPop_back(SListNode **plist)
{
    SListNode *p = *plist;
    //如果链表为空
   if (p == NULL || p ->next ==NULL)
   {
       free(p);
       *plist = NULL;
   }else{
        SListNode *pre = NULL;
        while (p ->next)
        {
            pre = p;
            p = p ->next;
        }
        pre ->next = NULL;
    }
    free(p);
}

//头部插入
void SListPush_Front(SListNode **plist,SLTDateType x)
{
    //assert(plist);
    SListNode *s = BuySListNode(x);
    SListNode *p = *plist;
    //如果链表为空
    if (*plist == NULL)
    {
        *plist = s;
    } else{
        s ->next = p;
        *plist = s;
    }

}

//头部删除
void SListPop_Front(SListNode **plist)
{
    //assert(plist);
    //如果链表为空
    if (*plist == NULL)
    {
        return;
    }
    //如果链表只有一个结点
    SListNode *cur = *plist;
    if (cur ->next == NULL)
    {
        free(cur);
        *plist = NULL;
    } else{
        SListNode *p = *plist;
        *plist = (*plist) ->next;
        free(p);
    }
}
//在pos之后插入x
void  SlistInsertAfter(SListNode**plist,SLTDateType x,SLTDateType key)
{
    assert(plist);
    SListNode *s = BuySListNode(x);
    if ((*plist) != NULL)
    {
        //找到往哪插的pos
        SListNode *pos = SListFind(*plist,key);
        if (pos == NULL)
        {
            return;
        } else{
            //pos存在
            s ->next = pos ->next;
            pos ->next = s;
        }
    } else{
        //链表为空
        SListPush_Back(plist,x);
    }
}

//删除pos位置之后的值(删除一个)
void SListEraseAfter(SListNode **plist,SLTDateType key)
{
    assert(plist);
    //如果链表为空或者如果链表中只有一个结点,且是要删除的位置
    if ((*plist) == NULL || (*plist) ->next == NULL)
    {
        return;
    }
    SListNode *pos = SListFind(*plist,key);
    if (pos != NULL)
    {
        if (pos ->next == NULL)
        {
            return;
        } else{
            pos ->next = pos ->next ->next;
        }
    } else{
        return;
    }
}

整个单链表的实现代码,以及测试函数

头文件:

#ifndef SLIST_SLIST_H
#define SLIST_SLIST_H

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


typedef int SLTDateType;

//定义链表结点
typedef  struct  SListNode
{
    SLTDateType data;
    struct SListNode* next;
}SListNode;

//声明
extern void InitSList(SListNode **pList);
extern void SListPush_Back(SListNode **plist,SLTDateType x);
extern void SListShow_List(SListNode *plist);
extern void SListPop_back(SListNode **plist);
extern void SListPush_Front(SListNode **plist,SLTDateType x);
extern void SListPop_Front(SListNode **plist);
extern SListNode* SListFind(SListNode *plist,SLTDateType key);
extern void  SlistInsertAfter(SListNode **plist,SLTDateType x,SLTDateType key);
extern void SListEraseAfter(SListNode **plist,SLTDateType key);
extern void SListDestory(SListNode **plist);


#endif //SLIST_SLIST_H

main.c

#include "SList.h"

void Menu()
{
    printf("****************************************************\n");
    printf("***1.Push_Back****************2.Pop_back************\n");
    printf("***3.Push_Front***************4.Pop_front***********\n");
    printf("***5.Show_List****************6.Find****************\n");
    printf("***7.InsertAfter**************8.EraseAfter**********\n");
    printf("***9.Destory******************0.Exit****************\n");
    printf("****************************************************\n");
    printf("Please select:\n");
}
enum {
    Exit,Push_Back,Pop_Back,Push_Front,Pop_Front,Show_List,Find,InsterAfter,EraseAfter,Destory
};

int main()
{
    SListNode * list;
    SLTDateType item,key,pos;
    InitSList(&list);
    int select = 1;
    while (select)
    {
        Menu();
        scanf("%d",&select);
        switch (select)
        {
            case Push_Back:
                printf("please enter the item(end by -1):\n");
                while ((scanf("%d",&item)) && item != -1)
                {
                    SListPush_Back(&list,item);
                }
                break;
            case Pop_Back:
                SListPop_back(&list);
                break;
            case Push_Front:
                printf("please enter the item(end by -1):\n");
                while ((scanf("%d",&item)) && item != -1)
                {
                    SListPush_Front(&list,item);
                }
                break;
            case Pop_Front:
                SListPop_Front(&list);
                break;
            case Show_List:
                SListShow_List(list);
                break;
            case Find:
                printf("please enter the key:\n");
                scanf("%d",&key);
                SListFind(list,key);
                break;
            case InsterAfter:
                printf("please enter the key:\n");//你要往哪插
                scanf("%d",&key);
                printf("please enter the item:\n");//插什么data
                scanf("%d",&item);
                SlistInsertAfter(&list,item,key);
                break;
            case EraseAfter:
                printf("please choose the key:\n");
                scanf("%d",&key);
                SListEraseAfter(&list,key);
                break;
            case Destory:
                SListDestory(&list);
                break;
            case Exit:
                printf("Exit successful!\n");
                select = 0;
                break;
            default:
                printf("select error,please select again!\n");
                break;
        }
    }
    return 0;
}

SList.c

//
// Created by 胡杨 on 2021/1/24.
//
#include "SList.h"

//初始化链表
void InitSList(SListNode **pList)
{
    //assert(pList);
    *pList = NULL;
}

//购买结点
static SListNode* BuySListNode(SLTDateType x)
{
    SListNode *s = NULL;
    s = (SListNode*)malloc(sizeof(SListNode));
    assert(s);
    s ->data = x;
    s ->next = NULL;
    return  s;
}

//尾部插入
void SListPush_Back(SListNode **plist,SLTDateType x)
{
    //assert(plist);
    SListNode *s = BuySListNode(x);
    SListNode *p = *plist;
    assert(s != NULL);
    //如果链表为空
    if (*plist == NULL)
    {
        *plist = s;
    } else{
        //链表不为空
        while (p ->next != NULL)
        {
            p = p ->next;
        }
        p ->next = s;
    }
}

//尾部删除
void SListPop_back(SListNode **plist)
{
    SListNode *p = *plist;
    //如果链表为空
   if (p == NULL || p ->next ==NULL)
   {
       free(p);
       *plist = NULL;
   }else{
        SListNode *pre = NULL;
        while (p ->next)
        {
            pre = p;
            p = p ->next;
        }
        pre ->next = NULL;
    }
    free(p);
}

//头部插入
void SListPush_Front(SListNode **plist,SLTDateType x)
{
    //assert(plist);
    SListNode *s = BuySListNode(x);
    SListNode *p = *plist;
    //如果链表为空
    if (*plist == NULL)
    {
        *plist = s;
    } else{
        s ->next = p;
        *plist = s;
    }

}

//头部删除
void SListPop_Front(SListNode **plist)
{
    //assert(plist);
    //如果链表为空
    if (*plist == NULL)
    {
        return;
    }
    //如果链表只有一个结点
    SListNode *cur = *plist;
    if (cur ->next == NULL)
    {
        free(cur);
        *plist = NULL;
    } else{
        SListNode *p = *plist;
        *plist = (*plist) ->next;
        free(p);
    }
}

//查找函数
SListNode* SListFind(SListNode *plist,SLTDateType key)
{
    assert(plist);
    SListNode *p = plist;
    while (p != NULL)
    {
        if (p ->data == key)
        {
            printf("the %d is find\n",p ->data);
            return p;
        }
        p = p ->next;
    }
    return NULL;
}

//在pos之后插入x
void  SlistInsertAfter(SListNode**plist,SLTDateType x,SLTDateType key)
{
    assert(plist);
    SListNode *s = BuySListNode(x);
    if ((*plist) != NULL)
    {
        //找到往哪插的pos
        SListNode *pos = SListFind(*plist,key);
        if (pos == NULL)
        {
            return;
        } else{
            //pos存在
            s ->next = pos ->next;
            pos ->next = s;
        }
    } else{
        //链表为空
        SListPush_Back(plist,x);
    }
}

//删除pos位置之后的值(删除一个)
void SListEraseAfter(SListNode **plist,SLTDateType key)
{
    assert(plist);
    //如果链表为空或者如果链表中只有一个结点,且是要删除的位置
    if ((*plist) == NULL || (*plist) ->next == NULL)
    {
        return;
    }
    SListNode *pos = SListFind(*plist,key);
    if (pos != NULL)
    {
        if (pos ->next == NULL)
        {
            return;
        } else{
            pos ->next = pos ->next ->next;
        }
    } else{
        return;
    }
}

//摧毁链表
void SListDestory(SListNode **plist)
{
    assert(plist);
    SListNode *p = *plist;
    SListNode *q = *plist;
    if (p == NULL)
    {
        return;
    } else{
        while (q)
        {
            q = p ->next;
            free(p);
            p = q;
        }
    }
    *plist = NULL;
}

//显示函数
void SListShow_List(SListNode *plist)
{
    //assert(plist);
    SListNode *p = plist;
    while (p)
    {
        printf("%d-->",p ->data);
        p = p ->next;
    }
    printf("Over\n");
}

本人还在初级阶段,有什么错误还希望大家提出来,我会虚心学习并改正错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值