C++实现单链表(2)

单链表操作之结点删除,结点插入,链表翻转

前面一节实现了链表的基本操作,本节实现链表常用操作,虽然很常用,实现起来却比较复杂。

1、结点删除

  删除结点可以按照位置删除,也可以按照数据删除,这里实现的是按照位置删除。在删除之前,取需要判断删除位置是否合法,以及删除的位置是否会大于链表的总长度。

template<typename Datatype>
inline void LinkList<Datatype>::Delete(int delete_location)
{
    if (0 >= delete_location || this->Length() <= delete_location)
        throw "删除位置错误";

    int count = 1;
    Node<Datatype>* p = this->first;
    while (count < delete_location)
    {
        count++;
        p = p->next;
    }
    /**
     * 当p为待插入位置的上一个元素时,退出循环
     */
    Node<Datatype>* q = p->next;
    p->next = q->next;
    //释放空间,删除干净
    delete q;
}

  这里了的遍历需要遍历到删除位置元素的前一个元素,因为遍历到删除元素无法向前遍历,除非是双向链表或者创建一个变量来存储前一个结点的指针,这里完全没有必要。同时删除元素也要将对应结点的空间释放掉,防止内存泄漏。

2、结点插入

  结点插入同样需要遍历到插入位置的前一个结点,同时允许插入位置大于链表总长度+1,实现尾插。同时插入结点是要申请堆区内存空间用来存储需要插入的结构体。

template<typename Datatype>
inline void LinkList<Datatype>::Insert(const Datatype& insert_data, int insert_location)
{
    if (0 >= insert_location || this->Length() + 1 < insert_location)
        throw "插入位置错误";

    int count = 1;
    Node<Datatype>* p = this->first;
    
    while (count < insert_location)
    {
        count++;
        p = p->next;
    }
    /**
     * 当p为待插入位置的上一个元素时,退出循环
     * 初始化待插入结点
     * 将节点用头插的方式插入链表中
     */
    Node<Datatype>* s = new Node<Datatype>;
    s->Data = insert_data;
    s->next = p->next;
    p->next = s;
}

3、链表翻转

链表翻转使用以下方法:

1-判断链表长度是否大于1,如果大于1,则进行第2步,否则,退出函数。

2-堆区开辟内存申请一个结点大小的内存空间,将其作为新链表头结点,初始化。

3-从头遍历原链表每个元素并依次将元素插入到新链表的头结点之后,释放原链表每个结点内存。

4-将原链表头指针指向新链表头结点。

template<typename Datatype>
inline void LinkList<Datatype>::Reverse()
{
    int length = this->Length();
    if (0 == length || 1 == length)    return;

    Node<Datatype>* p = this->first, * p_next = p->next;

    //如果链表长度小于等于1,初始化新链表头结点
    Node<Datatype> *p_tar = new Node<Datatype>;
    p_tar->next = nullptr;

    for (int i = 0; i < length; i++)
    {
        //为待插入新链表的结点分配空间
        Node<Datatype> *s = new Node<Datatype>;

        //待插入结点填入数据
        Datatype data = p_next->Data;
        s->Data = data;

        //新节点头插方式插入新链表
        s->next = p_tar->next;
        p_tar->next = s;

        //释放旧结点空间
        delete p;

        //p和p_next指针后移
        p = p_next;
        p_next = p_next->next;
    }
    //将新头结点指针赋值给first
    this->first = p_tar;
}

4、测试代码

#include <iostream>
#include <string>
#include "LinkList.hpp"

using namespace std;

int main()
{
    string string_array[] = { " This ", " is ", " string_list ", " test." };
    //使用带参构造数据域为string类型的链表
    LinkList<string>* list_string_p = new LinkList<string>
        (string_array, sizeof(string_array) / sizeof(string_array[0]));

    try 
    {
        cout << "链表带参构造后遍历:"; 
        list_string_p->PrintList();
        cout << "string链表第4个元素:" << list_string_p->Get(4) << endl;

        list_string_p->Insert(" a ", 3);
        cout << "在第三个位置插入a:";
        list_string_p->PrintList();

        list_string_p->Delete(3);
        cout << "删除第三个元素后:";
        list_string_p->PrintList();

        list_string_p->Reverse();
        cout << "链表翻转:";
        list_string_p->PrintList();

        //list_string_p->Empty();
        cout << "链表长度:" << list_string_p->Length() << endl;
    }
    catch (const char* catch_string)
    {
        cout << catch_string << endl;
    }

    delete list_string_p;
    system("pause");
    return 0;
}

5、测试结果

6、 总结

异常的测试也通过,这里不再演示。

 

新人才疏学浅,有错的地方敬请指正!!

本文来自博客园,作者:夏末终年,转载请注明出处:https://www.cnblogs.com/xiamozhongnian/p/15890390.html

 

posted @ 2022-02-15 20:05  夏末终年  阅读(44)  评论(0编辑  收藏  举报