数据结构之单链表

Posted 一棵灬胡杨树

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构之单链表相关的知识,希望对你有一定的参考价值。

线性链表

文章目录


一、什么是线性链表?

线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元既可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素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");


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

以上是关于数据结构之单链表的主要内容,如果未能解决你的问题,请参考以下文章

数据结构:链表

算法总结之 单链表的选择排序

单链表LRU

双链表算法之遍历

Day553.单链表 -数据结构和算法Java

用单链表实现栈 Push,Pop时间为O