链式存储(无头单向不循环链表)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhang21722668/article/details/82154916

1.链表的分类(8种)

  • 单向 | 双向
  • 有头 | 没有头
  • 有循环 | 无循环

2.顺序表 和 链表 的区别

顺序表 链表
一段连续空间 空间不连续
支持随机访问 不支持随机访问
任意位置进行插入删除不方便(可能需要搬移元素) 方便插入删除(改变几个指针的指向)
不适用于任意位置的插入删除 适用于任意位置的插入删除
增容过程需要开辟新空间,拷贝元素,释放旧空间 不需要
不需要频繁申请空间 频繁申请空间(会出现空间碎片)
缓存利用率比链表高

3.概念

  • 一个个空间
  • 空间中承载的数据
  • 空间之间用链式结构串起来(next)next==NULL 表示结尾

4.链表
增删(改)查

  • Push Back | Front | Pos
  • Pop Back | Front | Pos
  • Find Remove | RemoveAll

5.模块代码
【1.创建链表结构体】

typedef int DataType;

typedef struct SList
{
    DataType data;
    struct SList *pNext;
}SList;

【2.链表初始化】

void Init(SList **ppHead)
{
    *ppHead = NULL;
}

【3.打印链表】

void print(SList *pHead)
{
    SList *pNode;
    for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
    {
        printf("%2d->", pNode->data);
    }
    printf(" NULL\n");
}

【4.尾插】

void PushBack(SList **ppHead, DataType data)
{
    //链表为空
    SList *pNewNode = BuyNewNode(data);

    if (*ppHead == NULL){
        *ppHead = pNewNode; 
        return;
    }

    //正常情况
    //找到倒数第一个
    SList *pNode = *ppHead; 
    while (pNode->pNext != NULL){
        pNode = pNode->pNext;
    }

    pNewNode->pNext = pNode->pNext;
    pNode->pNext = pNewNode;
}

【5.头插】

void PushFront(SList **ppHead, DataType data)
{
    SList *pNewNode = BuyNewNode(data);

    pNewNode->pNext = *ppHead;
    *ppHead = pNewNode;
}

【6.尾删】

void PopBack(SList **ppHead)
{   //链表为空
    if (*ppHead == NULL){
        printf("链表已空!\n");
        return;
    }
    //只有一个结点
    if ((*ppHead)->pNext == NULL){
        free(*ppHead);
        *ppHead = NULL;
        return;
    }
    //两个以上结点
    //找倒数第二个结点
    SList *pNode, *pNext;
    pNode = *ppHead;
    while (pNode->pNext->pNext != NULL){
        pNode = pNode->pNext;
    }
    pNext = pNode->pNext;
    //pNode->pNext = pNext->pNext;
    pNode->pNext = NULL;
    free(pNext);
}

【7.头删】

void PopFront(SList **ppHead)
{   //链表为空
    if (*ppHead == NULL){
        printf("链表已空!\n");
        return;
    }
    //正常情况
    SList *pHead = *ppHead;
    SList *pNext = pHead->pNext;
    free(pHead);
    //pHead = NULL;错误
    *ppHead = pNext;
}

【8.指定位置前插入一个值】

void Insert(SList **ppHead, SList *pPosNode, DataType data)
{
    //1.找拆链子
    //2.Buy结点
    //3.把新结点挂在链子上
    //pPosNode一定在链子里面

    /*if (*ppHead == NULL && pPosNode == NULL){
        *ppHead = BuyNewNode(data);
        return;
    }*/

    if (*ppHead == pPosNode){
        PushFront(&ppHead, data);
        return;
    }
    //正常情况
    SList *pNode; 
    //结束后 pNode 就是 pPosNodede 前一个
    for (pNode = *ppHead; pNode->pNext != pPosNode; pNode = pNode->pNext){
    }
    SList *pNewNode = BuyNewNode(data);
    pNewNode->pNext = pPosNode;
    pNode->pNext = pNewNode;
}

【9.指定位置删除】

void Erase(SList **ppHead, SList *pPosNode)
{
    if (*ppHead == pPosNode){
        PopFront(ppHead);
        return;
    }
    SList *pNode;
    //结束后 pNode 就是 pPosNodede 前一个
    for (pNode = *ppHead; pNode->pNext != pPosNode; pNode = pNode->pNext){
    }
    pNode->pNext = pPosNode->pNext;
    free(pPosNode);
}

【10.查找】

//如果找到就返回装数据的结点指针
//如果没找到就返回NULL
SList *Find(SList *pHead, DataType data)
{
    SList *pNode;
    for (pNode = pHead; pNode != NULL; pNode = pNode->pNext){
        if (pNode->data == data){
            return pNode;
        }
    }
    return NULL;
}

【11.链表有多个相同元素删第一个】

void Remove(SList **ppHead, DataType data)
{
    SList *pPosNode = Find(*ppHead, data);
    if (pPosNode != NULL){
        Erase(ppHead, pPosNode);
    }
}

【12.链表中有多个相同元素,全部删去(一次遍历删完)】

void RemoveAll(SList **ppHead, DataType data)
{
    SList *pNode = *ppHead;
    SList *pDel;
    while (pNode->pNext != NULL){
        if (pNode->pNext->data == data){
            pDel = pNode->pNext;
            pNode->pNext = pDel->pNext;
            free(pDel);
        }
        else{
            pNode = pNode->pNext;
        }
    }
    if ((*ppHead)->data == data){
        PopFront(ppHead);
    }
}

【13.计算链表长度】

int Size(SList *pHead)
{
    int size  = 0;
    SList *pNode;
    for (pNode = pHead; pNode != NULL; pNode = pNode->pNext){
        size++;
    }
    return size;
}

【14.销毁链表】

/*
    1.遍历链表(每一个)
    2.把空间释放掉 free
*/
void Destroy(SList **ppHead)
{
    SList *pNode, *pNext;
    for (pNode = *ppHead; pNode != NULL; pNode = pNext){
        pNext = pNode->pNext;
        free(pNode);
    }
    *ppHead = NULL;
}

6.单向无头无循环链表完整代码

//SList.h
#ifndef __SList__H__
#define __SList__H__
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>

typedef int DataType;

typedef struct SList
{
    DataType data;
    struct SList *pNext;
}SList;

//初始化
void Init(SList **ppHead)
{
    *ppHead = NULL;
}

//打印
void print(SList *pHead)
{
    SList *pNode;
    for (pNode = pHead; pNode != NULL; pNode = pNode->pNext)
    {
        printf("%2d->", pNode->data);
    }
    printf(" NULL\n");
}

//创建新结点
static SList *BuyNewNode(DataType data)
{
    SList *pNewNode = (SList *)malloc(sizeof(SList));
    assert(pNewNode);
    pNewNode->data = data;
    pNewNode->pNext = NULL;

    return pNewNode;
}

//插入
/*
    1.要有空间
    2.把数据装进去
    3.把空间结点链接上去
        1)把t链子拆开
            找到拆的地方
        2)把上半段的next连到新结点上
        3)把新结点的next连到原来的下半段

*/

//尾插
void PushBack(SList **ppHead, DataType data)
{
    //链表为空
    SList *pNewNode = BuyNewNode(data);

    if (*ppHead == NULL){
        *ppHead = pNewNode; 
        return;
    }

    //正常情况
    //找到倒数第一个
    SList *pNode = *ppHead; 
    while (pNode->pNext != NULL){
        pNode = pNode->pNext;
    }

    pNewNode->pNext = pNode->pNext;
    pNode->pNext = pNewNode;
}

//头插
void PushFront(SList **ppHead, DataType data)
{
    SList *pNewNode = BuyNewNode(data);

    pNewNode->pNext = *ppHead;
    *ppHead = pNewNode;
}

//删除
/*
    1.拆链子
        找对地方
    2.把空间free
    3.把上半段直接连到下半段
*/

//尾删
void PopBack(SList **ppHead)
{   //链表为空
    if (*ppHead == NULL){
        printf("链表已空!\n");
        return;
    }
    //只有一个结点
    if ((*ppHead)->pNext == NULL){
        free(*ppHead);
        *ppHead = NULL;
        return;
    }
    //两个以上结点
    //找倒数第二个结点
    SList *pNode, *pNext;
    pNode = *ppHead;
    while (pNode->pNext->pNext != NULL){
        pNode = pNode->pNext;
    }
    pNext = pNode->pNext;
    //pNode->pNext = pNext->pNext;
    pNode->pNext = NULL;
    free(pNext);
}

//头删
void PopFront(SList **ppHead)
{   //链表为空
    if (*ppHead == NULL){
        printf("链表已空!\n");
        return;
    }
    //正常情况
    SList *pHead = *ppHead;
    SList *pNext = pHead->pNext;
    free(pHead);
    //pHead = NULL;错误
    *ppHead = pNext;
}

//在指定位置之前插入一个值
void Insert(SList **ppHead, SList *pPosNode, DataType data)
{
    //1.找拆链子
    //2.Buy结点
    //3.把新结点挂在链子上
    //pPosNode一定在链子里面

    /*if (*ppHead == NULL && pPosNode == NULL){
        *ppHead = BuyNewNode(data);
        return;
    }*/

    if (*ppHead == pPosNode){
        PushFront(&ppHead, data);
        return;
    }
    //正常情况
    SList *pNode; 
    //结束后 pNode 就是 pPosNodede 前一个
    for (pNode = *ppHead; pNode->pNext != pPosNode; pNode = pNode->pNext){
    }
    SList *pNewNode = BuyNewNode(data);
    pNewNode->pNext = pPosNode;
    pNode->pNext = pNewNode;
}

//指定位置删除 
void Erase(SList **ppHead, SList *pPosNode)
{
    if (*ppHead == pPosNode){
        PopFront(ppHead);
        return;
    }
    SList *pNode;
    //结束后 pNode 就是 pPosNodede 前一个
    for (pNode = *ppHead; pNode->pNext != pPosNode; pNode = pNode->pNext){
    }
    pNode->pNext = pPosNode->pNext;
    free(pPosNode);
}

//查找
//如果找到就返回装数据的结点指针
//如果没找到就返回NULL
SList *Find(SList *pHead, DataType data)
{
    SList *pNode;
    for (pNode = pHead; pNode != NULL; pNode = pNode->pNext){
        if (pNode->data == data){
            return pNode;
        }
    }
    return NULL;
}

//链表有多个相同元素,删第一个
void Remove(SList **ppHead, DataType data)
{
    SList *pPosNode = Find(*ppHead, data);
    if (pPosNode != NULL){
        Erase(ppHead, pPosNode);
    }
}

//链表中有多个相同元素,全部删去(一次遍历删完)
void RemoveAll(SList **ppHead, DataType data)
{
    SList *pNode = *ppHead;
    SList *pDel;
    while (pNode->pNext != NULL){
        if (pNode->pNext->data == data){
            pDel = pNode->pNext;
            pNode->pNext = pDel->pNext;
            free(pDel);
        }
        else{
            pNode = pNode->pNext;
        }
    }
    if ((*ppHead)->data == data){
        PopFront(ppHead);
    }
}

//计算链表长度
int Size(SList *pHead)
{
    int size  = 0;
    SList *pNode;
    for (pNode = pHead; pNode != NULL; pNode = pNode->pNext){
        size++;
    }
    return size;
}

//void EraseNotTailNode(pNode pos);
//int GetListLength(pList plist);


//销毁链表
/*
    1.遍历链表(每一个)
    2.把空间释放掉 free
*/
void Destroy(SList **ppHead)
{
    SList *pNode, *pNext;
    for (pNode = *ppHead; pNode != NULL; pNode = pNext){
        pNext = pNode->pNext;
        free(pNode);
    }
    *ppHead = NULL;
}

//test.c
#include"SList.h"

void TestSListPushBack()
{
    SList *pHead;
    Init(&pHead);
    PushBack(&pHead, 1);
    PushBack(&pHead, 2);
    PushBack(&pHead, 3);
    PushBack(&pHead, 4);
    print(pHead);
    Destroy(&pHead);
}

void TestSListPushFront()
{
    SList *pHead;
    Init(&pHead);
    PushFront(&pHead, 101);
    PushFront(&pHead, 102);
    PushFront(&pHead, 103);
    PushFront(&pHead, 104);
    print(pHead);
    Destroy(&pHead);
}

void TestSListPopBack()
{
    SList *pHead;
    Init(&pHead);
    PushBack(&pHead, 1);
    PushBack(&pHead, 2);
    PushBack(&pHead, 3);
    PushBack(&pHead, 4);
    print(pHead);
    PopBack(&pHead);
    print(pHead);
    PopBack(&pHead);
    print(pHead);
    PopBack(&pHead);
    print(pHead);
    PopBack(&pHead);
    print(pHead);
    PopBack(&pHead);
    print(pHead);
    PopBack(&pHead);
    print(pHead);
    Destroy(&pHead);
}

void TestSListPopFront()
{
    SList *pHead;
    Init(&pHead);
    PushBack(&pHead, 1);
    PushBack(&pHead, 2);
    PushBack(&pHead, 3);
    PushBack(&pHead, 4);
    print(pHead);
    PopFront(&pHead);
    print(pHead);
    PopFront(&pHead);
    print(pHead);
    PopFront(&pHead);
    print(pHead);
    PopFront(&pHead);
    print(pHead);
    PopFront(&pHead);
    print(pHead);
    Destroy(&pHead);
}

TestSListFindInsert()
{
    SList *pHead;
    Init(&pHead);
    PushBack(&pHead, 1);
    PushBack(&pHead, 2);
    PushBack(&pHead, 3);
    PushBack(&pHead, 4);
    print(pHead);
    SList *pPos = Find(pHead, 3);
    Insert(&pHead, pPos, 9);
    pPos = Find(pHead, 3);
    Insert(&pHead, pPos, 1);
    print(pHead);
    Destroy(&pHead);
}

void TestSListErase()
{
    SList *pHead;
    Init(&pHead);
    PushBack(&pHead, 1);
    PushBack(&pHead, 2);
    PushBack(&pHead, 3);
    PushBack(&pHead, 4);
    print(pHead);
    SList *pPos = Find(pHead, 3);
    Insert(&pHead, pPos, 9);
    pPos = Find(pHead, 3);
    Insert(&pHead, pPos, 1);
    print(pHead);
    pPos = Find(pHead, 3);
    Erase(&pHead, pPos);
    print(pHead);
    Destroy(&pHead);
}

void TestSListRemoveRemoveAll()
{
    SList *pHead;
    Init(&pHead);
    PushBack(&pHead, 1);
    PushBack(&pHead, 2);
    PushBack(&pHead, 1);
    PushBack(&pHead, 1);
    print(pHead);
    Remove(&pHead, 1);
    print(pHead);
    RemoveAll(&pHead, 1);
    print(pHead);
    Destroy(&pHead);
}

void TestSListSize()
{
    SList *pHead;
    Init(&pHead);
    PushBack(&pHead, 1);
    PushBack(&pHead, 2);
    PushBack(&pHead, 3);
    PushBack(&pHead, 4);
    print(pHead);
    printf("%d\n", Size(pHead));
    Destroy(&pHead);
}

int main()
{
    //TestSListPushBack();
    //TestSListPushFront();
    //TestSListPopBack();
    //TestSListPopFront();
    //TestSListFindInsert();
    //TestSListErase();
    //TestSListRemoveRemoveAll();
    //TestSListSize();
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhang21722668/article/details/82154916