C++链表类的封装详情介绍

yizhihongxing

C++中的链表是一种数据结构,它由一组节点组成,每个节点包含两个部分:一个存储数据的部分和一个指向下一个节点的指针。链表可以按照插入的顺序存储数据,因此它没有大小限制,也可以随时添加、删除和查询数据。在本文中,我们将介绍如何在C++中使用链表类来封装一个链表数据结构。

相关定义

节点类定义

为了构建链表,我们首先需要定义一个节点类,该类有两个成员变量:一个用于存储数据的数据成员,以及一个指向下一个节点的指针成员变量。同时,该类也应该提供公共的访问和更新成员函数来处理这些成员变量。

template<typename T>
class Node {
public:
    T data_;        //定义节点数据成员
    Node<T>* next_; //定义指向下一个节点的指针成员
public:
    Node() {} //默认构造函数
    Node(T d, Node<T>* n = nullptr) : data_(d), next_(n) {} //带参构造函数
    ~Node() {} //析构函数
};

链表类定义

首先,链表类需要一个定义节点的指针和一个记录链表大小的成员变量。此外,我们还需要提供一些基本操作,例如查找、插入和删除等成员函数。为了提高效率,在链表类的实现中使用头指针和尾指针来记录列表的开头和结尾部分。

在链表类定义中,我们需要注意以下几点:

  1. 链表类需要定义一个指向节点的指针作为列表的头指针;
  2. 定义一个指向节点的指针作为列表的尾指针;
  3. 定义一个整型变量保存列表的长度;
  4. 定义公共成员函数操作,如查找、插入和删除等。
template<typename T>
class LinkList {
private:
    Node<T>* head_; //指向节点的指针作为列表的头指针
    Node<T>* tail_; //指向节点的指针作为列表的尾指针
    int length_; //指向整型变量保存列表的长度
public:
    LinkList() : head_(nullptr), tail_(nullptr), length_(0) {}; //链表对象的构造函数
    ~LinkList(); //链表对象的析构函数
    bool empty(); //判断是否为空链表
    void clear(); //清空链表
    int length(); //链表长度
    bool get_element(int i, T& e); //获取指定索引位置的节点值
    int locate(const T& e); //查找值为e的节点
    bool insert(int i, const T& e); //在指定位置前插入值为e的节点
    bool remove(int i, T& e); //删除指定位置的节点
    void display(); //遍历输出链表
};

成员函数实现

析构函数

当链表对象被销毁时,需要逐个删除存储在链表中的所有节点。

template<typename T>
LinkList<T>::~LinkList() {
    clear();
}

判断链表是否为空

判断链表是否为空需要查看链表的长度,如果长度为0,则表示链表为空。

template<typename T>
bool LinkList<T>::empty() {
    return length_ == 0; //length_记录链表长度,为0则代表为空链表
}

清空链表

为了避免内存泄漏,链表在使用完后要及时清空。而清空链表就是从头至尾逐个删除链表中的节点。

template<typename T>
void LinkList<T>::clear() {
    Node<T>* p = head_;
    while (p) {
        head_ = p->next_;
        delete p;
        p = head_;
    }
    head_ = tail_ = nullptr;
    length_ = 0; //清空链表,length_为0
}

获取链表长度

由于每次添加或删除节点时,我们都会根据需要更新链表长度,所以可以直接返回长度值即可。

template<typename T>
int LinkList<T>::length() {
    return length_;
}

获取指定节点值

在链表中查找指定位置的节点并将值返回。如果索引超出链表长度,则返回false。

template<typename T>
bool LinkList<T>::get_element(int i, T& e) {
    if (i < 0 || i >= length_) {
        return false;
    }
    Node<T>* p = head_;
    int j = 0;
    while (p && j < i) {
        p = p->next_;
        ++j;
    }
    e = p->data_;
    return true;
}

查找指定值节点

在链表中查找指定值的节点。如果找到该节点,则返回它的位置,否则返回0。

template<typename T>
int LinkList<T>::locate(const T& e) {
    Node<T>* p = head_;
    int j = 0;
    while (p && p->data_ != e) {
        p = p->next_;
        j++;
    }
    if (!p) return 0;
    return j;
}

插入节点

在链表的任意位置插入一个新节点。如果索引超出链表长度,则返回false。

template<typename T>
bool LinkList<T>::insert(int i, const T& e) {
    if (i < 0 || i > length_) {
        return false;
    }
    Node<T>* new_node = new Node<T>(e);
    if (!new_node) {
        return false;
    }
    if (i == 0) {
        new_node->next_ = head_;
        head_ = new_node;
        if (!tail_) {
            tail_ = head_;
        }       
    } else {
        Node<T>* p = head_;
        int j = 0;
        while (p && j < i - 1) {
            p = p->next_;
            ++j;
        }
        new_node->next_ = p->next_;
        p->next_ = new_node;
        if (!new_node->next_) {
            tail_ = new_node;
        }
    }
    length_++;
    return true;
}

删除节点

在链表的任意位置删除一个节点。如果索引超出链表长度,则返回false。

template<typename T>
bool LinkList<T>::remove(int i, T& e) {
    if (i < 0 || i >= length_) {
        return false;
    }
    Node<T>* p = head_;
    if (i == 0) {
        e = head_->data_;
        head_ = head_->next_;
        if (!head_) {
            tail_ = nullptr;
        }       
    } else {
        int j = 0;
        while (p->next_ && j < i - 1) {
            p = p->next_;
            ++j;
        }
        e = p->next_->data_;
        p->next_ = p->next_->next_;
        if (!p->next_) {
            tail_ = p;
        }
    }
    length_--;
    return true;
}

遍历链表

遍历链表是指输出链表的所有节点,以便于查看链表内的元素数据。

template<typename T>
void LinkList<T>::display(){
    if(head_ == nullptr){
        std::cout<<"链表为空"<<std::endl;
    }else{
        Node<T>* p = head_;
        while(p!=nullptr){
            std::cout<<p->data_<<" ";
            p = p->next_;
        }
        std::cout << "\n";
    }
}

示例

示例1:插入、删除以及获取操作

下面的示例显示如何使用链表类封装一次插入、删除以及获取数据的操作。

#include<iostream>
#include"linklist.hpp"

int main(){
    LinkList<int> linklist;
    linklist.insert(0,1);
    std::cout<<"isEmpty: "<<linklist.empty()<<std::endl; //输出0
    linklist.insert(1,2);
    linklist.insert(2,3);
    linklist.display();
    int e = 0;
    linklist.remove(2,e);
    std::cout<<"remove element: "<<e<<std::endl; //输出3
    linklist.display();
    linklist.get_element(1,e);
    std::cout<<"get element: "<<e<<std::endl; //输出2
    linklist.display();

    return 0;
}

执行结果:

isEmpty: 0
1 2 3 
remove element: 3
1 2 
get element: 2
1 2 

示例2:查找、长度以及清空操作

下面的示例显示如何使用链表类封装一次查找、长度以及清空的操作。

#include<iostream>
#include"linklist.hpp"

int main(){
    LinkList<int> linklist;
    linklist.insert(0,1);
    linklist.insert(1,2);
    linklist.insert(2,3);
    linklist.display();
    std::cout<<"length: "<<linklist.length()<<std::endl; //输出3
    int e = 0;
    int len = linklist.locate(2);
    std::cout<<"locate: "<<len<<std::endl; //输出2
    linklist.clear();
    std::cout<<"isEmpty: "<<linklist.empty()<<std::endl; //输出1

    return 0;
}

执行结果:

1 2 3 
length: 3
locate: 2
isEmpty: 1

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++链表类的封装详情介绍 - Python技术站

(0)
上一篇 2023年6月25日
下一篇 2023年6月25日

相关文章

  • C++如何处理内联虚函数

    C++如何处理内联虚函数的完整攻略 在C++中,内联函数和虚函数是两个常用的特性。内联函数可以提高程序的执行效率,而虚函数可以实现多态性。但是,内联函数和虚函数的结合使用会带来一些问题,例如内联虚函数的处理。本文将为您提供一份详细的C++如何处理内联虚函数的完整攻略,包括内联函数和虚函数的基本概念、内联虚函数的处理方法和两个示例说明。 内联函数和虚函数的基本…

    other 2023年5月5日
    00
  • TMS320DM642学习—第二篇(软件环境搭建+工程文件结构)

    TMS320DM642学习—第二篇(软件环境搭建+工程文件结构) 本文将介绍如何搭建TMS320DM642的软件开发环境,并介绍其工程文件结构。 软件环境搭建 首先,我们需要下载并安装CCS(Code Composer Studio)软件,这是一款集成了TI处理器开发工具的IDE。TI官网提供了CCS的免费下载,并提供了对应的安装流程说明。安装完CCS后…

    其他 2023年3月28日
    00
  • 从零开始打造mock平台-核心篇

    以下是详细讲解“从零开始打造mock平台-核心篇的完整攻略,过程中至少包含两条示例说明”的标准Markdown格式文本: 从零开始打造mock平台-核心篇 Mock平台是一种用于模拟API接口数据的工具,可以帮助开发人员在开发过程中快速构建和测试API接口。本攻略将介绍从零开始打造mock平台的核心步骤和技术。 步骤一:选择Mock平台框架 可以选择以下几种…

    other 2023年5月10日
    00
  • Go语言中的方法、接口和嵌入类型详解

    Go语言中的方法、接口和嵌入类型详解 方法 Go语言中,方法是一种作用于特定类型变量的函数。它类似于C++或者Java中的方法。在一个类型中定义方法给了这个类型的对象被调用这个方法的可能。在Golang中,方法的语法格式如下: func (receiver type) methodName(parameters) (results) { // 方法体 } 其…

    other 2023年6月26日
    00
  • Composition API思想封装NProgress示例详解

    我将为你详细讲解“Composition API思想封装NProgress示例详解”的完整攻略。 简介 首先,我们需要了解什么是Composition API及NProgress。 Composition API是Vue.js 3.0中新引入的一种API风格,它提供了更明确、更简洁、更灵活的代码结构和组合方式,让我们能够更快速地编写可维护性更高的代码。 而N…

    other 2023年6月25日
    00
  • C++如何处理内联虚函数

    C++如何处理内联虚函数 在C++中,内联函数是被广泛应用的一种优化技术,它能够使函数在编译的时候被直接插入到调用处,从而避免了函数调用的开销。而虚函数则是面向对象编程的重要特性,使得派生类能够覆盖基类的函数实现。那么问题来了,如果想要将一个虚函数定义为内联函数,该怎么做呢? 首先,我们需要明确一个内联函数的特性:它的定义必须在每个使用它的地方都可见。而虚函…

    其他 2023年3月28日
    00
  • VB6.0怎么使用文件对话框控件?

    当你需要让用户选择文件(如打开或保存文件),文件对话框控件是一个非常有用的工具。在VB6.0中,你可以通过以下步骤使用文件对话框控件: 步骤1:添加文件对话框控件 将文件对话框控件添加到你的窗体控件中。这可以通过在窗体设计器中拖动和放置文件对话框控件或直接编写代码实现。以下是一个在窗体1中添加文件对话框控件的示例代码: Private OpenFileDia…

    other 2023年6月27日
    00
  • 判断数据库web是否分离的技巧

    判断数据库Web是否分离的技巧有以下几个方面: 查看数据库连接字符串 首先,判断Web是否连接了数据库,可以查看Web应用程序的连接字符串。该连接字符串通常存储在Web.config或app.config文件中,表示应用程序与数据库之间的通信方式。如果连接字符串中包含IP地址或域名,则表明Web应用程序连接了外部数据库。如果连接字符串中使用的是localho…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部