Basic operations of a singly linked list

Linked list:

A set of arbitrary storage units is used to store the nodes of the linear table. This set of storage units can be continuous or discontinuous, or even scattered in any position in the memory.

typedef int DataType;
typedef struct Node
{
    DataType _data;
    struct Node* _next;
}Node, *PNode;

A node includes two fields:
data field: used to store the value of the node;
pointer field: used to store the address (or location) information of the immediate successor of the data element.
Singly linked list: there is only one next pointer field!
Since the first node in the linear list has no predecessor, a head pointer H should be set to point to the first node;
since the last node of the linear list has no direct successor, the pointer field of the last node of the specified singly linked list is "null" (NULL).

headless singly linked list

#include "Node.h"

// 创建新节点函数
PNode BuyNewNode(DataType data)
{
    PNode _new = (PNode)malloc(sizeof(Node));
    if (NULL == _new)
    {
        printf("内存申请失败\n");
        return NULL;
    }

    _new->_data = data;
    _new->_next = NULL;
    return _new;
}

// 尾插操作函数
void SListPushBack(PNode* pHead, DataType data)
{
    PNode _new = NULL;
    // 参数检验
    assert(pHead);

    _new = BuyNewNode(data);
    if (NULL == _new)
    {
        return;
    }
    else
    {
        // 申请到了新节点
        if (NULL == (*pHead))
        {
            // 如果单链表是空的话,让头指针直接指向新节点
            *pHead = _new;
        }
        else
        {
            // 链表非空
            PNode pCur = NULL;
            pCur = (*pHead);

            // 找链表的尾
            while (!(pCur->_next == NULL))
            {
                pCur = pCur->_next;
            }

            // 链接起来
            pCur->_next = _new;
        }
    }
}

// 尾删操作函数
void SListPopBack(PNode* pHead)
{
    PNode pCur = NULL; // 
    PNode pPre = NULL; // 用来保存当前节点前一个节点

    // 参数检验
    assert(pHead);

    pCur = *pHead;
    pPre = pCur;

    // 找单链表的尾,并用pPre保存前一个节点
    while (!(pCur->_next == NULL))
    {
        pPre = pCur;
        pCur = pCur->_next;
    }

    pPre->_next = NULL; // 找到尾之后直接让pPre->_next赋空
    free(pCur); // 释放掉从单链表摘下的节点
    pCur = NULL; // 避免野指针
}

// 头插操作函数
void SListPushFront(PNode* pHead, DataType data)
{
    PNode _new = NULL;

    // 参数检验
    assert(pHead);

    _new = BuyNewNode(data);
    if (NULL == _new)
    {
        return;
    }
    else
    {
        // 成功申请到新节点
        if (*pHead == NULL)
        {
            // 空链表 直接让头指针指向新节点
            *pHead = BuyNewNode(data);
            return;
        }
        // 链表非空 进行头插
        _new = BuyNewNode(data);
        _new->_next = *pHead;
        *pHead = _new;// 修改头指针
    }
}

// 头删操作函数
void SListPopFront(PNode* pHead)
{
    PNode pCur = NULL;

    // 参数检验
    assert(pHead);

    pCur = *pHead;
    if(NULL == pCur)
    {
        printf("链表为空\n");
        return;
    }
    // 单链表非空 
    *pHead = pCur->_next; // 让头指针指向头的_next域
    free(pCur); // 释放pCur
    pCur = NULL; // 避免野指针
}

// 在链表中查找值为data的元素,找到后返回值为data的结点 
PNode SListFind(PNode pHead, DataType data)
{
    PNode pCur = NULL;

    // 参数检验
    assert(pHead);

    pCur = pHead;
    // 遍历单链表 查找值为data的元素
    while (pCur != NULL)
    {
        if (pCur->_data == data)
        {
            return pCur; // 找到了返回
        }
        pCur = pCur->_next; // pCur后移
    }

    return NULL; // 找不到返回NULL
}

// 在pos位置插入值为data的结点 
void SListInsert(PNode* pHead, PNode pos, DataType data)
{
    PNode pPre = NULL;
    PNode pCur = NULL;
    PNode _new = NULL;

    // 参数检验
    assert(pHead);

    pCur = *pHead;
    pPre = pCur;

    if (pCur->_next == NULL)
    {
        // 链表为空
        if (pCur == pos)
        {
            // 头插
            _new = BuyNewNode(data);
            if (_new == NULL)
            {
                return;
            }
            else
            {
                pHead = &_new;
            }
        }
        else
        {
            // 链表位置不合法
            printf("pos位置不合法\n");
            return;
        }
    }
    // 链表不为空
    while (pCur != NULL)
    {
        if (pos == pCur)
        {
            _new = BuyNewNode(data);
            if (_new == NULL)
            {
                return;
            }
            else
            {
                _new->_next = pPre->_next;
                pPre->_next = _new;
            }
            return;
        }
        else
        {
            pPre = pCur;
            pCur = pCur->_next;
        }       
    }
    // 已经遍历完了单链表 仍没找到pos位置
    printf("pos位置不合法\n");
    return;
}

// 删除pos位置的结点 
void SListErase(PNode* pHead, PNode pos)
{
    PNode pCur = NULL;
    PNode pPre = NULL;

    // 参数检验
    assert(pHead);

    pCur = *pHead;
    pPre = pCur;
    if (pCur == NULL)
    {
        printf("链表为空!!!\n");
        return;
    }

    while (pCur != NULL)
    {
        if (pos == pCur)
        {
            pPre->_next = pCur->_next;
            free(pCur);
            pCur = NULL;
            return;
        }
        else
        {
            pPre = pCur;
            pCur = pCur->_next;
        }
    }
    // 已遍历单链表
    printf("pos位置不合法\n");
    return;
}

// 判断链表是否为空  为空返回1 不为空返回0
int SListEmpty(PNode pHead)
{
    if (pHead == NULL)
    {
        return 1;
    }
    return 0;
}

// 销毁链表 
void SListDestroy(PNode* pHead)
{
    PNode p = NULL;
    PNode q = NULL;
    // 参数检验
    assert(pHead);

    p = *pHead;
    while (p->_next != 0)
    {
        // 不是链尾时
        q = p->_next; // 让q指向头节点的后继节点
        free(p);
        p = q; // 让p和q都指向后继节点
    }

    *pHead = NULL; // 将头指针赋空
}
// 链表遍历
void PrintNode(PNode pHead)
{
    PNode pCur = NULL;
    // 参数检验
    assert(pHead);

    pCur = pHead;
    printf("单链表中所有元素:");

    while (pCur != NULL)
    {
        printf("%d->", pCur->_data);
        pCur = pCur->_next;
    }

    printf("NULL\n");

}
// Node.h
#pragma once

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

typedef int DataType;
typedef struct Node
{
    DataType _data;
    struct Node* _next;
}Node, *PNode;

// 尾插 
void SListPushBack(PNode* pHead, DataType data);

// 尾删 
void SListPopBack(PNode* pHead);

// 头插 
void SListPushFront(PNode* pHead, DataType data);

// 头删 
void SListPopFront(PNode* pHead);

// 在链表中查找值为data的元素,找到后返回值为data的结点 
PNode SListFind(PNode pHead, DataType data);

// 在pos位置插入值为data的结点 
void SListInsert(PNode* pHead, PNode pos, DataType data);

// 删除pos位置的结点 
void SListErase(PNode* pHead, PNode pos);

// 判断链表是否为空 
int SListEmpty(PNode pHead);

// 销毁链表 
void SListDestroy(PNode* pHead);

// 链表遍历
void PrintNode(PNode pHead);

1. Test singly linked list tail insertion and tail deletion operations, and traverse the singly linked list

#include "Node.h"

void TestNodePushBack_PopBack()
{
    PNode pHead = NULL; // 头指针,并初始化
    SListPushBack(&pHead, 1); // 尾插元素
    SListPushBack(&pHead, 2);
    SListPushBack(&pHead, 3);
    SListPushBack(&pHead, 4);
    PrintNode(pHead); // 遍历打印单链表

    SListPopBack(&pHead); // 尾删一个元素
    PrintNode(pHead); // 遍历打印单链表

    SListDestroy(&pHead); // 销毁单链表
}

// 主函数
int main()
{
    TestNodePushBack_PopBack(); // 调用测试函数
    system("pause");
    return 0;
}

Test Results:
write picture description here

2. Test singly linked list header insertion and header deletion operations, and traverse the singly linked list

#include "Node.h"

void TestNodePushFront_PopFront()
{
    PNode pHead = NULL; // 头指针,并初始化
    SListPushFront(&pHead, 4); // 头插元素
    SListPushFront(&pHead, 3);
    SListPushFront(&pHead, 2);
    SListPushFront(&pHead, 1);
    PrintNode(pHead); // 遍历打印单链表

    SListPopFront(&pHead); // 头删一个元素
    PrintNode(pHead); // 遍历打印单链表

    SListDestroy(&pHead); // 销毁单链表

}

// 主函数
int main()
{
    TestNodePushFront_PopFront();
    system("pause");
    return 0;
}

Test results:
write picture description here
3. Test singly linked list search, specified position insertion, specified position deletion operations

#include "Node.h"

void TestNodeFind_Insert_Erase()
{
    PNode pHead = NULL;
    PNode ret_Find = NULL;
    SListPushBack(&pHead, 1);
    SListPushBack(&pHead, 2);
    SListPushBack(&pHead, 4);
    PrintNode(pHead);

    ret_Find = SListFind(pHead, 4);
    SListInsert(&pHead, ret_Find, 3);
    PrintNode(pHead);

    SListErase(&pHead, ret_Find);
    PrintNode(pHead);

    SListDestroy(&pHead); // 销毁单链表

}

// 主函数
int main()
{
    TestNodeFind_Insert_Erase(); // 调用测试函数
    system("pause");
    return 0;
}

Test results:
write picture description here
4. Finally, let's talk about the destruction of the singly linked list. In order to avoid memory leaks, the singly linked list should be destroyed a little after using it.

Please comment, please correct me if I am wrong, thank you

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325639790&siteId=291194637