无头单链表的增、删、改、查等相关操作

我们都知道,链表是线性表的一种,那为什么会有链表这种数据存储结构呢?
原因大致可以总结为以下三点:

  • 线性表的长度不确定,难以事先确定数组长度。
  • 存储空间必须是连续的,容易造成存储空间的“碎片”现象。
  • 插入和删除操作需要移动大量元素。

为了克服以上缺点,我们可以采用链式存储的线性表,即单链表。

初识单链表

  • 定义:一种链式存储的线性表,用一组地址任意的存储单元存放线性表的数据元素,称存储单元为一个节点,且每一个节点的指针域只有一个。
  • 分类:单链表、双链表、循环链表
  • 单链表又分为有头节点和不带头节点的单链表,两者的区别在于有头节点的单链表在其第一个节点之前还有一个节点,称为头节点,用于存放信息;而不带头节点的单链表没有头节点,即头指针后直接是链表的第一个节点。
    注:在本篇博客中,pHead代表链表第一个节点
    这里写图片描述

  • 存储结构:

typedef struct Node
{
    struct Node* _pNext;
    DataType _data;
}Node, *PNode;

其中,Node为结构名,即节点类型定义;PNode为指向链表的节点的指针类型;因为节点包含两个域,数据域和指针域,所以结构体中只需定义这两个不同的域可。

无头单链表的基本运算


初始化
无头单链表的初始化就是让单链表的头指针pHead指向空。

void SListInit(PNode* pHead)//链表初始化
{
    assert(pHead);
    *pHead = NULL;
}

尾插和尾删

尾插就是在单链表的最后一个节点后插入一个节点,在满足单链表不为空的前提下,可分为两种情况:


  1. 链表中只有一个头指针
  2. 链表中已经存在元素
    这里写图片描述

尾删就是尾插的逆过程,当链表只有一个元素时,直接释放,并让头指针指向空,若链表有多个元素时,定义两个指针pCur、pTail, pTail用来遍历链表,以便寻找最后一个节点的位置,pCur用来标记pTail 。
相关代码如下:
void SListPushBack(PNode* pHead, DataType data)//尾插
{
    assert(pHead);
    if (NULL == *pHead)
    {
        *pHead = BuySListNode(data);
    }
    else
    {
        PNode pCur = *pHead;
        while(pCur->_pNext)
        {
            pCur = pCur->_pNext;
        }
        pCur->_pNext=BuySListNode(data);
    }
}

void SListPopBack(PNode* pHead)//尾删
{
    assert(pHead);
    if (NULL == *pHead)
    {
        return;
    }
    else if (NULL == (*pHead)->_pNext)
    {
        free(*pHead);
        *pHead = NULL;
    }
    else
    {
        PNode pTail = *pHead;
        PNode pCur = NULL;
        while (pTail->_pNext)
        {
            pCur = pTail;
            pTail = pTail->_pNext;
        }
        pCur->_pNext = NULL;
        free(pTail);
    }
}

头插与头删
头插就是在链表第一个元素前插入一个新节点。
这里写图片描述

头删就是删除链表的第一个元素,同时改变pHead的指向。
比如:链表存有1-2-3-4-5 五个元素,则pHead指向1,现将1删除,则pHead将指向2

void SListPushFront(PNode* pHead, DataType data)//头插
{
    assert(pHead);
    PNode pNewNode = BuySListNode(data);
    pNewNode->_pNext = *pHead;
    *pHead = pNewNode;
}

void SListPopFront(PNode* pHead)//头删
{
    if (NULL == *pHead)
    {
        return;
    }
    else if (NULL== (*pHead)->_pNext)
    {
        free(*pHead);
        *pHead = NULL;
    }
    else
    {
        PNode pCur = *pHead;
        pCur = pCur->_pNext;
        free(*pHead);
        *pHead = pCur;
    }
}

任意节点的插入和删除
任意节点的插入和删除,也是改变节点之间指针域的操作。
这里写图片描述
删除同样是插入的反操作,只要熟悉了每一步操作指针是如何改变的,这一步就很容易了。在此就不做详细介绍了。

void SListInsert(PNode* pHead, PNode pos, DataType data)// 在链表pos位置后插入结点data 
{
    assert(pHead);
    if (NULL == *pHead || NULL == pos)
    {
        return;
    }
    PNode pNewNode = NULL; 
    pNewNode = BuySListNode(data);
    if (NULL == pNewNode)
    {
        return;
    }
    pNewNode->_pNext = pos->_pNext;
    pos->_pNext=pNewNode;
}

void SListErase(PNode* pHead, PNode pos)// 删除链表pos位置上的结点 
{
    assert(*pHead);
    if (NULL == *pHead || NULL == pos)
    {
        return;
    }
    if (pos == *pHead)
    {
        SListPopFront(pHead);
    }
    else
    {
        PNode pCur = *pHead;
        while (pCur && pCur->_pNext != pos)
        {
            pCur = pCur->_pNext;
        }
        if (pCur)
        {
            pCur->_pNext = pos->_pNext;
            free(pos);
        }
    }
}

查找值为data的节点
定义一个pCur,使它指向pHead,依次遍历链表,若data=pCur->data,返回pCur;
若不相等,则令pCur=pCur->next;循环执行此步骤。

PNode SListFind(PNode pHead, DataType data)// 查找值为data的结点,返回该结点在链表中的位置 
{
    assert(pHead);
    PNode pCur = pHead;
    while (pCur)
    {
        if (data == pCur->_data)
        {
            return pCur;
        }
        else
        {
            pCur = pCur->_pNext;
        }
    }
    return NULL;
}

无头单链表的全部代码

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

typedef int DataType;

typedef struct Node
{
    struct Node* _pNext;
    DataType _data;
}Node, *PNode;

///////////////////////////////////////////
//函数声明

void SListInit(PNode pHead);
void SListPushBack(PNode* pHead, DataType data);
PNode BuySListNode(DataType data);
void SListPopBack(PNode* pHead);
void SListPushFront(PNode* pHead, DataType data);
void SListPopFront(PNode* pHead);
void SListInsert(PNode* pHead, PNode pos, DataType data);
void SListErase(PNode* pHead, PNode pos);
PNode SListFind(PNode pHead, DataType data);
void SListDestroy(PNode* pHead);
void SListClear(PNode* pHead);
int SListSize(PNode pHead);
PNode SListBack(PNode pHead);


/////////////////////////////////////
//具体实现

void SListInit(PNode* pHead)//链表初始化
{
    assert(pHead);
    *pHead = NULL;
}

void SListPushBack(PNode* pHead, DataType data)//尾插
{
    assert(pHead);
    if (NULL == *pHead)
    {
        *pHead = BuySListNode(data);
    }
    else
    {
        PNode pCur = *pHead;
        while(pCur->_pNext)
        {
            pCur = pCur->_pNext;
        }
        pCur->_pNext=BuySListNode(data);
    }
}

void SListPopBack(PNode* pHead)//尾删
{
    assert(pHead);
    if (NULL == *pHead)
    {
        return;
    }
    else if (NULL == (*pHead)->_pNext)
    {
        free(*pHead);
        *pHead = NULL;
    }
    else
    {
        PNode pTail = *pHead;
        PNode pCur = NULL;
        while (pTail->_pNext)
        {
            pCur = pTail;
            pTail = pTail->_pNext;
        }
        pCur->_pNext = NULL;
        free(pTail);
    }
}



PNode BuySListNode(DataType data)// 获取结点 
{
    PNode pNewNode = (PNode)malloc(sizeof(Node));
    if (NULL == pNewNode)
    {
        return NULL;
    }
    pNewNode->_pNext = NULL;
    pNewNode->_data = data;
    return pNewNode;
}

void SListPushFront(PNode* pHead, DataType data)//头插
{
    assert(pHead);
    PNode pNewNode = BuySListNode(data);
    pNewNode->_pNext = *pHead;
    *pHead = pNewNode;
}

void SListPopFront(PNode* pHead)//头删
{
    if (NULL == *pHead)
    {
        return;
    }
    else if (NULL== (*pHead)->_pNext)
    {
        free(*pHead);
        *pHead = NULL;
    }
    else
    {
        PNode pCur = *pHead;
        pCur = pCur->_pNext;
        free(*pHead);
        *pHead = pCur;
    }
}


PNode SListFind(PNode pHead, DataType data)// 查找值为data的结点,返回该结点在链表中的位置 
{
    assert(pHead);
    PNode pCur = pHead;
    while (pCur)
    {
        if (data == pCur->_data)
        {
            return pCur;
        }
        else
        {
            pCur = pCur->_pNext;
        }
    }
    return NULL;
}

void SListInsert(PNode* pHead, PNode pos, DataType data)// 在链表pos位置后插入结点data 
{
    assert(pHead);
    if (NULL == *pHead || NULL == pos)
    {
        return;
    }
    PNode pNewNode = NULL; 
    pNewNode = BuySListNode(data);
    if (NULL == pNewNode)
    {
        return;
    }
    pNewNode->_pNext = pos->_pNext;
    pos->_pNext=pNewNode;
}

void SListErase(PNode* pHead, PNode pos)// 删除链表pos位置上的结点 
{
    assert(*pHead);
    if (NULL == *pHead || NULL == pos)
    {
        return;
    }
    if (pos == *pHead)
    {
        SListPopFront(pHead);
    }
    else
    {
        PNode pCur = *pHead;
        while (pCur && pCur->_pNext != pos)
        {
            pCur = pCur->_pNext;
        }
        if (pCur)
        {
            pCur->_pNext = pos->_pNext;
            free(pos);
        }
    }
}

int SListSize(PNode pHead)//求链表中节点个数
{
    assert(pHead);
    int count = 0;
    PNode pCur = pHead;
    while (pCur)
    {
        count++;
        pCur = pCur->_pNext;
    }
    return count;
}


PNode SListBack(PNode pHead)//获取链表中的最后一个结点,返回该结点的地址
{
    assert(pHead);
    PNode pCur = pHead;
    if (NULL == pHead)
        return NULL;
    while (pCur->_pNext)
    {
        pCur = pCur->_pNext;
    }
    return pCur;
}

void SListDestroy(PNode* pHead)//销毁单链表 
{
    SListClear(pHead);
}

void SListClear(PNode* pHead)//清空链表
{
    assert(pHead);
    while (*pHead)
    {
        if (NULL == (*pHead)->_pNext)
        {
            free(*pHead);
            *pHead = NULL;
        }
        else
        {
            PNode pCur = *pHead;
            while (pCur->_pNext != NULL)
            {
                SListPopBack(pHead);
            }
        }
    }
}


void PrintSList(PNode pHead)
{
    PNode p = pHead;
    while (p)
    {
        printf("%d",p->_data);
        p = p->_pNext;
    }
    printf("\n");
}


//////////////////////////////////////

void test1()
{
    PNode List=NULL;
    PNode pos = NULL;
    SListInit(&List);
    SListPushBack(&List, 1);
    SListPushBack(&List, 2);
    SListPushBack(&List, 3);
    SListPushBack(&List, 4);
    SListPushBack(&List, 5);
    PrintSList(List);
    printf("size=%d\n", SListSize(List));
    printf("\n");

    SListPopBack(&List);
    PrintSList(List);
    printf("size=%d\n", SListSize(List));
    printf("\n");


    SListPushFront(&List, 6);
    SListPushFront(&List, 7);
    SListPushFront(&List, 8);
    PrintSList(List);
    printf("size=%d\n", SListSize(List));
    printf("\n");

    SListPopFront(&List);
    SListPopFront(&List);
    PrintSList(List);
    printf("size=%d\n", SListSize(List));
    printf("\n");

    pos = SListFind(List, 2);
    if (pos)
    {
        SListInsert(&List, pos, 9);
    }
    PrintSList(List);
    printf("size=%d\n", SListSize(List));
    printf("\n");

    SListErase(&List, pos);
    PrintSList(List);
    printf("size=%d\n", SListSize(List));
    printf("\n");

    printf("最后一个节点是:%d\n", SListBack(List));

}

////////////////////////////////////////
int main()
{
    test1();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wwt_lb1314/article/details/80345650