C++ 空链表插入数据的操作

Posted 穿迷彩服的鲨鱼

tags:

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


前言

  • 我们说链表是一种动态数据结构,是因为在创建链表时,无须知道链表的长度。
  • 当插入一个节点时,我们只需要为新节点分配内存,然后调整指针的指向来确保新节点被链接到链表当中。
  • 内存分配不是在链表创建时一次性完成的,而是每添加一个节点分配一次内存。
  • 由于没有闲置的内存,链表的空间效率比数组高。

如果单向链表的定义如下

struct ListNode 
{
    int m_nValue;
    ListNode* m_pNext;
};

一、那么往该链表的末尾添加一个节点的C++代码如下:

void AddToTail(ListNode** pHead, int value)
{
    ListNode* pNew = new ListNode();
    pNew->m_nValue = value;
    pNew->m_pNext = nullptr;

    if (*pHead == nullptr)
    {
        *pHead = pNew;
    }
    else
    {
        ListNode* pNode = *pHead;
        while (pNode->m_pNext != nullptr)
        {
            pNode = pNode->m_pNext;
        }
        pNode->m_pNext = pNew;
    }
}
  • 在上面的代码中,我们要特别注意函数的第一个参数pHead是一个指向指针的指针。
  • 当我们往一个空链表中插入节点时,新插入的节点就是链表的头指针。
  • 由于此时会改动头指针,因此必须把pHead参数设为指向指针的指针,否则除了这个函数pHead仍然是一个空指针。

  • 由于链表中的内存不是一次性分配的,因而我们无法保证链表的内存和数组的一样是连续的。
  • 因此,想要在链表中找到它的第i个节点,那么我么只能从头结点开始,沿着指向下一个节点的指针遍历链表,它的时间效率为O(n)。
  • 而在数组中,我们可以根据下表在O(1)时间内找到第i个元素。

二、下面是在哦链表中找到第一个含有某值的节点并删除该节点的代码:

void RemoveNode(ListNode** pHead, int value)
{
    if (pHead == nullptr || *pHead == nullptr)
    {
        return;
    }

    ListNode* pToBeDeleted = nullptr;
    if ((*pHead)->m_nValue == value)
    {
        pToBeDeleted = *pHead;
        *pHead = (*pHead)->m_pNext;
    }
    else
    {
        ListNode* pNode = *pHead;
        while (pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue != value)
        {
            pNode = pNode->m_pNext;
        }

        if (pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue == value)
        {
            pToBeDeleted = pNode->m_pNext;
            pNode->m_pNext = pNode->m_pNext->m_pNext;
        }
    }

    if (pToBeDeleted != nullptr)
    {
        delete pToBeDeleted;
        pToBeDeleted = nullptr;
    }
}

测试

/*
* 我们说链表是一种动态数据结构,是因为在创建链表时,无须知道链表的长度。
* 当插入一个节点时,我们只需要为新节点分配内存,然后调整指针的指向来确保新节点被链接到链表当中。
* 内存分配不是在链表创建时一次性完成的,而是每添加一个节点分配一次内存。
* 由于没有闲置的内存,链表的空间效率比数组高。
*/
#include <iostream>
using namespace std;
/*
* 如果单向链表的定义如下
*/
struct ListNode 
{
    int m_nValue;
    ListNode* m_pNext;
};

/*
* 那么往该链表的末尾添加一个节点的C++代码如下:
*/
void AddToTail(ListNode** pHead, int value)
{
    ListNode* pNew = new ListNode();
    pNew->m_nValue = value;
    pNew->m_pNext = nullptr;

    if (*pHead == nullptr)
    {
        *pHead = pNew;
    }
    else
    {
        ListNode* pNode = *pHead;
        while (pNode->m_pNext != nullptr)
        {
            pNode = pNode->m_pNext;
        }
        pNode->m_pNext = pNew;
    }
}
/*
* 在上面的代码中,我们要特别注意函数的第一个参数pHead是一个指向指针的指针。
* 当我们往一个空链表中插入节点时,新插入的节点就是链表的头指针。
* 由于此时会改动头指针,因此必须把pHead参数设为指向指针的指针,否则除了这个函数pHead仍然是一个空指针。
*/

/*
* 由于链表中的内存不是一次性分配的,因而我们无法保证链表的内存和数组的一样是连续的。
* 因此,想要在链表中找到它的第i个节点,那么我么只能从头结点开始,沿着指向下一个节点的指针遍历链表,它的时间效率为O(n)。
* 而在数组中,我们可以根据下表在O(1)时间内找到第i个元素。
*/

/*
* 下面是在哦链表中找到第一个含有某值的节点并删除该节点的代码:
*/
void RemoveNode(ListNode** pHead, int value)
{
    if (pHead == nullptr || *pHead == nullptr)
    {
        return;
    }

    ListNode* pToBeDeleted = nullptr;
    if ((*pHead)->m_nValue == value)
    {
        pToBeDeleted = *pHead;
        *pHead = (*pHead)->m_pNext;
    }
    else
    {
        ListNode* pNode = *pHead;
        while (pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue != value)
        {
            pNode = pNode->m_pNext;
        }

        if (pNode->m_pNext != nullptr && pNode->m_pNext->m_nValue == value)
        {
            pToBeDeleted = pNode->m_pNext;
            pNode->m_pNext = pNode->m_pNext->m_pNext;
        }
    }

    if (pToBeDeleted != nullptr)
    {
        delete pToBeDeleted;
        pToBeDeleted = nullptr;
    }
}

void Print(ListNode* pHead)
{
    ListNode* pNode = pHead;
    while (pNode!=nullptr)
    {
        cout << pNode->m_nValue << " ";
        pNode = pNode->m_pNext;
    }
}

int main()
{
    ListNode* pHead = nullptr;
    AddToTail(&pHead, 1);
    AddToTail(&pHead, 2);
    AddToTail(&pHead, 3);
    AddToTail(&pHead, 4);
    cout << "尾插后:";
    Print(pHead);

    cout << endl << endl;
    RemoveNode(&pHead, 2);

    cout << "删除节点2后:";
    Print(pHead);

    return 0;
}

以上是关于C++ 空链表插入数据的操作的主要内容,如果未能解决你的问题,请参考以下文章

头插法链表的基本操作:创建空链表,插入结点,遍历链表,求链表长度,查找结点,删除结点

如何使用C++ STL中的链表list

c++主要程序二

尾插法链表拆分

头插法链表拆分

数据结构线性表链式存储实现