C++ 手动实现单向循环链表(课后作业版)

news2024/9/20 2:35:13

单向循环链表,并实现增删查改等功能

首先定义节点类,类成员包含当前节点的值, 指向下一个节点的指针

循环链表的尾节点指向头节点

节点定义:

//node definition
template <typename T>
class Node {
public:
    T value;
    Node<T>* next;

    Node() {}
    Node(const T& value) {
        this->value = value;
        next = nullptr;
    }
    Node(const T& value, const Node<T>& next) {
        this->value = value;
        this->next = next;
    }
};

然后是链表类的定义,主要包含了增删查改等功能

//LinkList_cycle definition
template <typename T>
class LinkList_cycle {
public:
    Node<T>* headnode;

    LinkList_cycle();
    LinkList_cycle(const T* arr, int len);  //array initial
    LinkList_cycle(const LinkList_cycle<T>& link);
    ~LinkList_cycle();
    LinkList_cycle<T>& push_back(T n);
    LinkList_cycle<T>& push_front(T n);
    LinkList_cycle<T>& insert(int pos, int n, T* arr);
    LinkList_cycle<T>& pop_front();
    LinkList_cycle<T>& pop_back();
    LinkList_cycle<T>& remove(int pos, int num);
    LinkList_cycle<T>& reverse();
    T& operator[](int n);
    T& at(int n);
    LinkList_cycle<T>& replace(int pos, int n, T* arr);
    int getLen() {return len;}
    void clear() {this->~LinkList_cycle();}
    void display();
private:
    int len = 0;
    Node<T>* getNode(int n);

};

各个函数解释:

LinkList_cycle();      默认构造函数

LinkList_cycle(const T* arr, int len);      一般构造函数

LinkList_cycle(const LinkList_cycle<T>& link)           拷贝构造函数

~LinkList_cycle();     析构函数

LinkList_cycle<T>& push_back(T n);    在尾部添加一个元素

LinkList_cycle<T>& push_front(T n);     在头部添加一个元素

LinkList_cycle<T>& insert(int pos, int n, T* arr);   在pos处插入n个元素

LinkList_cycle<T>& pop_front();    删除第一个节点

LinkList_cycle<T>& pop_back();    删除最后一个节点

LinkList_cycle<T>& remove(int pos, int num);     删除pos开始的num个元素

LinkList_cycle<T>& reverse();     反转链表

T& operator[](int n);     重载[ ]运算符,返回第n个节点的值

T& at(int n);                 与[ ]一样,只不过会检查索引是否越界

LinkList_cycle<T>& replace(int pos, int n, T* arr);    替换n个节点

int getLen() {return len;}     返回长度,因为len是private

void clear() {this->~LinkList_cycle();}    清除链表

void display();    显示链表所有元素

Node<T>* getNode(int n);     返回第n个节点的指针,是private函数,在其他函数中经常用到
 

完整代码:

#include <iostream>
using namespace std;

//node definition
template <typename T>
class Node {
public:
    T value;
    Node<T>* next;

    Node() {}
    Node(const T& value) {
        this->value = value;
        next = nullptr;
    }
    Node(const T& value, const Node<T>& next) {
        this->value = value;
        this->next = next;
    }
};

//LinkList_cycle definition
template <typename T>
class LinkList_cycle {
public:
    Node<T>* headnode;

    LinkList_cycle();
    LinkList_cycle(const T* arr, int len);  //array initial
    LinkList_cycle(const LinkList_cycle<T>& link);
    ~LinkList_cycle();
    LinkList_cycle<T>& push_back(T n);
    LinkList_cycle<T>& push_front(T n);
    LinkList_cycle<T>& insert(int pos, int n, T* arr);
    LinkList_cycle<T>& pop_front();
    LinkList_cycle<T>& pop_back();
    LinkList_cycle<T>& remove(int pos, int num);
    LinkList_cycle<T>& reverse();
    T& operator[](int n);
    T& at(int n);
    LinkList_cycle<T>& replace(int pos, int n, T* arr);
    int getLen() {return len;}
    void clear() {this->~LinkList_cycle();}
    void display();
private:
    int len = 0;
    Node<T>* getNode(int n);

};

//default constructor
template <typename T>
LinkList_cycle<T>::LinkList_cycle() {
    headnode = nullptr;
    len = 0;
}

//normal constructor
template <typename T>
LinkList_cycle<T>::LinkList_cycle(const T* arr, int len) {
    Node<T>* temp = nullptr;
    Node<T>* node = nullptr;
    if ( len < 0 ) {
        cout << "[error]: illegal length of LinkList_cycle" << endl;
        exit(0);
    }
    node = new Node<T>(arr[0]);
    headnode = node;
    temp = node;
    for ( int i = 1; i < len; i++ ) {
        node = nullptr;
        node = new Node<T> (arr[i]);
        temp->next = node;
        temp = temp->next;
    }
    temp->next = headnode;;
    this->len = len;
}

//copy constructor
template <typename T>
LinkList_cycle<T>::LinkList_cycle(const LinkList_cycle<T>& link) {
    this->len = link.getLen();
    this->headnode = link.headnode;
}

//deconstructor
template <typename T>
LinkList_cycle<T>::~LinkList_cycle() {
    if ( headnode == nullptr || len == 0 ) {
        headnode = nullptr;
        len = 0;
        return;
    }
    this->len = 0;
    Node<T>* temp1 = headnode;
    Node<T>* temp2 = headnode;  //保存headnode
    while ( headnode != nullptr ) {
        temp1 = headnode;
        headnode = headnode->next;
        delete temp1;
        if ( headnode == temp2 ) //如果next指向headnode了,说明当前的temp1就是最后一个节点了
            break;
        temp1 = nullptr;
    }
    headnode = nullptr;
}

//display all elements in LinkList_cycle<T>
template <typename T>
void LinkList_cycle<T>::display() {
    if ( this->len == 0 ) {
        cout << "[warning]: can not display empty linkedlist" << endl;
        return;
    }
    Node<T> *node = headnode;
    for ( int i = 0; i < len; i++ ) {
        cout << node->value << " ";
        node = node->next;
    }
    if ( node != headnode ) {
        cout << "[error]: the last node->next do not point to headnode, check again" << endl;
    }
    node = nullptr;
    cout << endl;
}

//add one node at the last position
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::push_back(T n) {
    Node<T> *node = this->getNode(len-1); //获取指向第len-1个node的指针,即len-2节点的next,所以node就是指向最后节点的指针

    if ( node->next == headnode ) {   //再加一层保护
        Node<T> *temp = new Node<T>(n);  //创建新node
        node->next = temp;           //将最后一个节点的next指向新node
        temp->next = headnode;       //将新node->next指向headnode
        this->len++;
    }
    return *this;
}

//add one node at the first position
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::push_front(T n) {
    Node<T>* node_new = new Node<T>(n);   //新节点
    Node<T> *node_end = this->getNode(len-1);   //最后节点
    node_new->next = headnode;            //新节点的next指向第一个节点
    node_end->next = node_new;            //最后节点的next指向新节点
    headnode = node_new;                  //再让headnode指向新节点
    this->len++;
    return *this;
}

//insert elements to LinkList_cycle
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::insert(int pos, int n, T* arr) {
    if ( pos > len-1 || len < 0 ) {
        cout << "[error]: illegal insert position, please check again" << endl;
        exit(0);
    }
    Node<T>* node_N = getNode(len-1); //前半部分
    Node<T>* temp = node_N->next;    //后半部分
    Node<T>* node_new = nullptr;     //新增加的
    for ( int i = 0; i < n; i++ ) {
        node_new = new Node<T> (arr[n-1-i]);
        node_new->next = temp;
        temp = node_new;
        node_new = nullptr;
    }
    node_N->next = temp;
    if ( pos == 0)    //唯有再0处插入的时候,需要改变头节点,其实对pos=0,一直push_front也行
        headnode = temp;
    this->len += n;
    return *this;
}

//delete the first element
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::pop_front() {
    if ( this->len == 0 ) {
        cout << "[error]: LinkList_cycle don't has any element" << endl;
        exit(0);
    }
    Node<T>* temp = headnode;  //先复制一份headnode
    headnode = headnode->next;  //headnode 前进一步
    delete temp;             //把第一个节点释放掉
    this->len--;
    temp = getNode(len-1);   //获取最后一个节点
    temp->next = headnode;   //把最后一个节点的next指向新的headnode
    return *this;
}

//delete the last element
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::pop_back() {
    if ( this->len == 0 ) {
        cout << "[error]: LinkList_cycle don't has any element" << endl;
        exit(0);
    }
    Node<T>* temp1 = getNode(len-2);
    Node<T>* temp2 = temp1->next;
    delete temp2;
    temp1->next = headnode;
    this->len--;
    return *this;
}

//get the last node pointer
template <typename T>
Node<T>* LinkList_cycle<T>::getNode(int n) {
    if ( n > len-1 || n < 0) {
        cout << "[warning]: index out of range" <<endl;
    }
    n = n%len;
    if ( n < 0 )
        n = n + len;
    Node<T> *node = headnode;
    for( int i = 0; i < n; i++ ) {
        node = node->next;
    }
    return node;
}

//remove n elements
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::remove(int pos, int num) {
    if ( pos > len-1 || len < 0 ) {
        cout << "[error]: illegal remove position, please check again" << endl;
        exit(0);
    } else if ( pos + num > len) {
        cout << "[error]: remove index out of range" << endl;
        exit(0);
    }
    Node<T>* node_N = getNode(pos-1);
    Node<T>* node_N_num = getNode(pos+num);
    Node<T>* temp = getNode(pos);
    while ( 1 ) {
        Node<T>* node = temp;
        temp = temp->next;
        if ( temp == node_N_num ) {
            break;
        }
        delete node;
    }
    if ( pos == 0 ) {   //如果从0位置开始删除,要修改头节点
        headnode = node_N_num;
        node_N->next = headnode;
    }
    node_N->next = node_N_num;
    this->len -= num;
    return *this;
}

//reverse LinkList_cycle
template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::reverse() {
    const int num = len;
    T arr[num];
    Node<T>* temp = headnode;
    for ( int i = 0; i < this->len; i++ ) {
        arr[i] = temp->value;
        temp = temp->next;
    }
    temp = headnode;
    for ( int i = 0; i < this->len; i++ ) {
        temp->value = arr[len-i-1];
        temp = temp->next;
    }
    return *this;
}

template <typename T>
T& LinkList_cycle<T>::operator[](int n) {
    return this->getNode(n)->value;
}

template <typename T>
LinkList_cycle<T>& LinkList_cycle<T>::replace(int pos, int n, T* arr) {
    if ( pos > len-1 || len < 0 ) {
        cout << "[error]: illegal remove position, please check again" << endl;
        exit(0);
    } else if ( pos + n > len) {
        cout << "[error]: remove index out of range" << endl;
        exit(0);
    }
    Node<T>* temp = nullptr;
    if ( pos == 0 )
        temp = headnode;
    else
        temp = this->getNode(pos);
    for ( int i = 0; i < n; i++ ) {
        temp->value = arr[i];
        temp = temp->next;
    }
    return *this;
}

int main(){
    int arr[]{1,2,4,5,0};
    LinkList_cycle<int> link(arr, sizeof(arr)/sizeof(int));
    cout << "LinkLint init with arr: " <<endl;
    link.display();
    cout << "push_back:" << endl;
    link.push_back(34);
    link.display();
    cout << "push_front:" << endl;
    link.push_front(10);
    link.display();
    cout << "insert:" << endl;
    link.insert(0,4,arr);
    link.display();
    cout << "pop_front:" << endl;
    link.pop_front();
    link.display();
    cout << "pop_back:" << endl;
    link.pop_back();
    link.display();
    cout << "remove:" << endl;
    link.remove(0,3);
    link.display();
    cout << "[] operator:" << endl;
    cout << link[2] << endl;
    cout << "replace:" << endl;
    int a[] = {6,5,2};
    link.replace(0, sizeof(a)/sizeof(int), a);
    link.display();
    cout << "LinkList_cycle reserve:" << endl;
    link.reverse();
    link.display();
    cout << "clear:" << endl;
    link.clear();
    cout << "len=" << link.getLen() << endl;
    link.display();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/31261.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue的生命周期快速入门

图示 流程 new Vue()实例化一个vue实例&#xff0c;然后init初始化event 和 lifecycle&#xff0c; 其实这个过程中分别调用了3个初始化函数&#xff08;initLifecycle(), initEvents(), initRender()&#xff09;&#xff0c;分别初始化了生命周期&#xff0c;事件以及定义cr…

k8s 资源管理及查看命令

关注 迪答数据 公众号获取更多 技术/数据 干货文章 文章传送门&#xff1a;数据治理之指标体系管理 管理容器的计算资源 参考文档&#xff1a; Kubernetes Managing Compute Resources for Containers(opens new window)https://kubernetes.io/docs/concepts/configuration/m…

go slice 扩容机制

前言 go语言没有ArrayList这样的封装&#xff0c;但是官方原生提供slice&#xff0c;底层就是数组存储&#xff0c;并且能自动扩容&#xff0c;相较于ArrayList的默认10&#xff0c;扩容5&#xff0c;slice的逻辑是有区别的。slice默认容量0。 demo go版本号 huahuaMac-min…

第一章 数据库绪论

数据库绪论 数据管理的三个阶段 人工管理阶段 文件系统阶段 数据库系统阶段 基本术语 数据&#xff08;Data&#xff09; 计算机用来描述事物的记录&#xff08;文字&#xff0e;图形&#xff0e;图像&#xff0e;声音&#xff09;数据的形式本身并不能完全表达其内容&a…

Transformer Fusion for Indoor RGB-D Semantic Segmentation

如何聚合多尺度特征这是一个问题&#xff0c;现有的方法大多通过卷积来实现&#xff0c;而很少在特征融合的地方使用长距离依赖&#xff0c;因此对于大物体的分割就会有挑战。本文提出基于transformer的融合策略&#xff0c;来更好的建模上下文。 TransD-Fusion包含①&#xff…

SpringBoot SpringBoot 开发实用篇 6 监控 6.4 info 端点指标控制

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇6 监控6.4 info 端点指标控制6.4.1 问题引入6.4.2 info 端点指标控制…

CleanMyMac4.12最新版mac系统内存空间清理教程

CleanMyMac X可以优化Mac系统。mac系统用久了&#xff0c;用CleanMyMac清理一下效果还不错。可用来清理系统的缓存、日志、语言和垃圾文件&#xff0c;还能卸载应用程序。 Mac是不需要安装任何杀毒软件的&#xff0c;虽然不用杀毒&#xff0c;但是日常的清理还是有必要的&#…

单机高性能网络模型

传统网络模型 PPC和prefork 优点 实现简单 缺点 PPC&#xff1a;fork代价高&#xff0c;性能低父子进程通信要用IPC&#xff0c;监控统计等实现会比较复杂OS的上下文切换会限制并发连接数&#xff0c;一般几百 案例 世界上第一个Web服务器CERN httpd采用PPC模式Apache MP…

简单网页制作代码 HTML+CSS+JavaScript香港美食(8页)

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

Spring 5有哪些新特性?这份spring5高级编程带你深入剖析,直击P8!

spring Spring 框架可以说是Java 世界最为成功的框架&#xff0c;在企业实际应用中&#xff0c;大部分的企业架构都基于Spring 框架。它的成功来自于理念&#xff0c;而不是技术&#xff0c;它最为核心的理念是IoC &#xff08;控制反转&#xff09;和AOP &#xff08;面向切面…

Flutter高仿微信-第28篇-好友详情-查看个人头像

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 实现代码&#xff1a; /*** Author : wangning* Email : maoning20080809163.co…

Redis如何实现持久化(AOF、RDB、混合模式)的优缺点

&#x1f468;‍&#x1f4bb;个人主页&#xff1a; 才疏学浅的木子 &#x1f647;‍♂️ 本人也在学习阶段如若发现问题&#xff0c;请告知非常感谢 &#x1f647;‍♂️ &#x1f4d2; 本文来自专栏&#xff1a; Redis ❤️ 支持我&#xff1a;&#x1f44d;点赞 &#x1f33…

OpenStackds集群部署(一)

一、OpenStack简介 Openstack体系架构 1. Openstack服务之间的关系 2.体系架构 3. 硬件要求 4. 网络架构 1.1 什么是OpenStack OpenStack是把一堆计算机资源和一堆存储服务器放到世界上不同的地方&#xff0c;然后通过这个OpenStack提供的不同服务程序连接起来&#xff0…

Linux(基于Centos7)(二)

文章目录一、任务介绍二、任务实施三、任务扩展一、任务介绍 Linux服务器配置与管理&#xff08;基于Centos7.2&#xff09;任务目标&#xff08;一&#xff09; 实施该工单的任务目标如下&#xff1a; 知识目标 1、熟悉Linux文件权限的表示方法。 2、了解改变文件权限的两种…

使用内存技术实现 HTAP 的可行性

万籁 “俱寂” 时&#xff0c;一家知名 IT 研究与顾问咨询机构的发声&#xff0c;给关系型数据库这个平静的池塘丢了颗巨石&#xff1a;2014 年&#xff0c;Gartner 正式提出了 HTAP 这个概念。 Gartner’s definition in 2014: utilizes in-memory computing technologies to …

查阅必备----常用的SQL语句,配语句和图解超详细,不怕你忘记

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 **收录于专栏 数据库 ⭐查阅必备–常用的SQL语句⭐ 文章目录⭐查阅必备--常用的SQL语句⭐一&#xff0c;关键语句大全&am…

驱动——设备树属性获取相关实验

完成设备树属性获取相关实验 通过键名获取数值相关API获取设备树属性 1、要获取的属性如下所示&#xff1a; /*mynode0x12345678{ compatible "hqyj,mynode";//字符串 astring"hello 22071";//字符串 uint <0xaabbccdd 0x11223344>;//32位无符号…

SpringBoot SpringBoot 开发实用篇 6 监控 6.5 health 端点指标控制

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇6 监控6.5 health 端点指标控制6.5.1 问题引入6.5.2 health 端点指标…

十二、虚拟 DOM 和 render() 函数(1)

本章概要 虚拟DOMrender()函数 Vue.js 之所以执行性能高&#xff0c;一个很重要的原因就是它的虚拟 DOM 机制。 12.1 虚拟 DOM 浏览器在解析 HTML 文档时&#xff0c;会将文档中的元素、注释、文本等标记按照它们的层级关系组织成一棵树&#xff0c;这就是熟知的 DOM 树。元…

MCE | LYTAC 与靶向蛋白降解技术

靶向蛋白降解 (TPD) 是一种有效性的&#xff0c;高度选择性的诱发蛋白降解方式。近年来&#xff0c;以 PROTAC 为代表的 TPD 技术的研究如火如荼。PROTAC 主要降解的是胞内蛋白&#xff0c;实际上&#xff0c;有 40% 的基因产物为胞外和膜相关蛋白&#xff0c;如生长因子、细胞…