Vector<T> 动态数组(模板语法)

C++数据结构与算法 目录

本文前驱课程

1 C++自学精简教程 目录(必读)

2 动态数组 Vector(难度1)

其中,2 是 1 中的一个作业。2 中详细讲解了动态数组实现的基本原理。

本文目标

1 学会写基本的C++类模板语法;

2 为以后熟练使用 STL 打下基础;

3 为更进一步的阅读和掌握更多的C++库打下基础;

模板语法的学习最恰当的方式就是和非模板代码对比学习。

本文的内容只是在 2 动态数组 Vector(难度1)的基础上,把代码改造为模板语法。

除此之外,不添加任何内容。

模板语法介绍

当类的成员变量是不确定的类型的时候,我们使用模板类( template class)来实现这样的类。

模板类的定义如下:

    template<typename T>  
    struct Vector{
        T data;//成员变量 data 的类型不确定,写成 T
    };

解释说明:

(1)template 表示后续代码中有类型是不确定的,先用typename T当中的T表示类型;

(2)typename表示T是一个未来才能确定的类型

(3)确定T的类型的方式就是创建一个Vector对象的时候在<>中指定:

 Vector<int> arr;  //这条语句表示用int替换代码中的T

非模板语法与模板语法差异对比图

模板语法和非模板语法对比1

模板语法和非模板语法对比2

代码与注释如下

#include<iostream>
#include <iomanip>
#include <cassert>
using namespace std;

//------下面的代码是用来测试你的代码有没有问题的辅助代码,你无需关注------
#include <algorithm>
#include <cstdlib>
#include <iostream> 
#include <vector>
#include <utility>
using namespace std;
struct Record { Record(void* ptr1, size_t count1, const char* location1, int line1, bool is) :ptr(ptr1), count(count1), line(line1), is_array(is) { int i = 0; while ((location[i] = location1[i]) && i < 100) { ++i; } }void* ptr; size_t count; char location[100] = { 0 }; int line; bool is_array = false; bool not_use_right_delete = false; }; bool operator==(const Record& lhs, const Record& rhs) { return lhs.ptr == rhs.ptr; }std::vector<Record> myAllocStatistic; void* newFunctionImpl(std::size_t sz, char const* file, int line, bool is) { void* ptr = std::malloc(sz); myAllocStatistic.push_back({ ptr,sz, file, line , is }); return ptr; }void* operator new(std::size_t sz, char const* file, int line) { return newFunctionImpl(sz, file, line, false); }void* operator new [](std::size_t sz, char const* file, int line)
{ return newFunctionImpl(sz, file, line, true); }void operator delete(void* ptr) noexcept { Record item{ ptr, 0, "", 0, false }; auto itr = std::find(myAllocStatistic.begin(), myAllocStatistic.end(), item); if (itr != myAllocStatistic.end()) { auto ind = std::distance(myAllocStatistic.begin(), itr); myAllocStatistic[ind].ptr = nullptr; if (itr->is_array) { myAllocStatistic[ind].not_use_right_delete = true; } else { myAllocStatistic[ind].count = 0; }std::free(ptr); } }void operator delete[](void* ptr) noexcept {Record item{ ptr, 0, "", 0, true }; auto itr = std::find(myAllocStatistic.begin(), myAllocStatistic.end(), item); if (itr != myAllocStatistic.end()) { auto ind = std::distance(myAllocStatistic.begin(), itr); myAllocStatistic[ind].ptr = nullptr; if (!itr->is_array) { myAllocStatistic[ind].not_use_right_delete = true; } else { myAllocStatistic[ind].count = 0; }std::free(ptr); }}
#define new new(__FILE__, __LINE__)
struct MyStruct { void ReportMemoryLeak() { std::cout << "Memory leak report: " << std::endl; bool leak = false; for (auto& i : myAllocStatistic) { if (i.count != 0) { leak = true; std::cout << "leak count " << i.count << " Byte" << ", file " << i.location << ", line " << i.line; if (i.not_use_right_delete) { cout << ", not use right delete. "; }	cout << std::endl; } }if (!leak) { cout << "No memory leak." << endl; } }~MyStruct() { ReportMemoryLeak(); } }; static MyStruct my; void check_do(bool b, int line = __LINE__) { if (b) { cout << "line:" << line << " Pass" << endl; } else { cout << "line:" << line << " Ohh! not passed!!!!!!!!!!!!!!!!!!!!!!!!!!!" << " " << endl; exit(0); } }
#define check(msg)  check_do(msg, __LINE__);
//------上面的代码是用来测试你的代码有没有问题的辅助代码,你无需关注------

//注意:禁止修改Vector的定义,包括禁止给Vector添加成员变量;
//可以添加私有成员函数,如果你认为需要的话

template<typename T>
struct Vector
{
public:
    Vector();
    Vector(int n, T value);
    Vector(const Vector& from);
    Vector(int* begin, int* end);
    ~Vector();
    int size() const;
    //只读元素
    //参考 https://zhuanlan.zhihu.com/p/539451614
    const T& operator[](int n)const { return m_data[n]; }
    //写入元素
    T& operator[](int n) { return m_data[n]; }
    void push_back(T value);
    bool empty() const;// your job 1
    void clear();// your job 2
    Vector& operator = (const Vector& from);// your job 4
private:
    void copy(const Vector& from);// your job 3
private:
    int m_element_cout;
    int m_capacity;
    T* m_data;//定义一个元素类型待定的数组起始元素的指针
    //请忽略下面这个成员变量,这个成员变量不影响你的实现,当它不存在即可。
};

//模板类的成员函数都要以下面的template语法开始,和类声明的地方一样
template<typename T>
Vector<T>::Vector()
{
    m_element_cout = 0;
    m_capacity = 10;
    m_data = new int[m_capacity];
}

template<typename T>
Vector<T>::Vector(int n, T value) :Vector()
{
    for (int i = 0; i < n; i++)
        push_back(value);
}

template<typename T>
Vector<T>::Vector(const Vector& from)
{
    m_element_cout = from.m_element_cout;
    m_capacity = from.m_capacity;
    m_data = new int[m_capacity];
    for (int i = 0; i < m_element_cout; i++)
    {
        m_data[i] = from.m_data[i];
    }
}

template<typename T>
Vector<T>::Vector(int* begin, int* end) :Vector()
{
    for (int* p = begin; p < end; p++)
    {
        push_back(*p);
    }
}

template<typename T>
Vector<T>::~Vector()
{
    delete[] m_data;
}

template<typename T>
int Vector<T>::size() const
{
    return m_element_cout;
}

template<typename T>
void Vector<T>::push_back(T value)
{
    if (m_element_cout < m_capacity)
    {
        m_data[m_element_cout] = value;
        m_element_cout++;
    }
    else
    {
        int* p;
        p = new T[2 * m_capacity];
        for (int j = 0; j < m_element_cout; j++)
        {
            p[j] = m_data[j];
        }
        p[m_element_cout] = value;
        m_element_cout = m_element_cout + 1;
        m_capacity = 2 * m_capacity;
        delete[]m_data;
        m_data = p;
    }
}

//(1) your code for : Vector empty()






//(2) your code for : Vector clear()







//(3) your code for : Vector copy()







//(4) your code for : Vector operator =









void test1(void)
{
    Vector<int> v;//创建一个存放int变量的容器v
    int i;
    check(v.size() == 0);
    for (i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    for (int i = 0; i < 10; i++)
    {
        check(v[i] == i);
    }
    check(v.size() == 10);
}
void test2(void)
{
    int n = 100000;
    Vector<int> v;
    int i;
    check(v.size() == 0);
    for (i = 0; i < n; i++)
    {
        v.push_back(i);
    }
    for (int i = 0; i < n; i++)
    {
        assert(v[i] == i);
    }
    check(v.size() == n);
}
void print(Vector<int>& v, const std::string& msg)
{
    std::cout << "The contents of " << msg.c_str() << " are:";
    for (int i = 0; i != v.size(); ++i)
    {
        std::cout << ' ' << v[i];
    }
    std::cout << '\n';
}
void test3()
{
    Vector<int> a;

    Vector<int> first;                   // empty vector of ints
    check(first.empty() == true && first.size() == 0);
    Vector<int> second(4, 100);                       // four ints with value 100
    check(second.empty() == false);
    check(second.size() == 4);
    Vector<int> fourth(second);                       // a copy of third
    check(fourth.size() == second.size());

    int myints[] = { 16,2,77,29 };
    Vector<int> fifth(myints, myints + sizeof(myints) / sizeof(int));
    check(fifth.empty() == false);
    check(fifth[0] == 16);
    check(fifth[3] == 29);
    check(fifth.size() == sizeof(myints) / sizeof(int));
    print(fifth, "fifth");//The contents of fifth are:16 2 77 29 
    fifth.push_back(30);
    check(fifth[4] == 30);
    check(fifth.size() == 5);
    print(fifth, "fifth");//The contents of fifth are:16 2 77 29 30 
    check(fifth.size() == sizeof(myints) / sizeof(int) + 1);
    first = fifth = fifth;
    print(first, "first");//The contents of first are:16 2 77 29 30 
    check(first.empty() == false && first.size() == fifth.size());
    Vector<int> a1(myints, myints + sizeof(myints) / sizeof(int));
    //下面大括号是作用域,用来把代码分开互不干扰,这样就可以创建相同的变量名字了,就不用为了起很多不同的变量名而烦恼了。
    {
        Vector<int> b(a1);
        b.push_back(2);
        check(b[4] == 2);
    }
    {
        Vector<int> c;
        c = a1;
    }
    check(a1.size() == sizeof(myints) / sizeof(int));
    {
        Vector<int> c;
        c = fifth;
        c[0] = 1;
        check(c[0] == 1);
    }
}

int main()
{
    test1();
    test2();
    test3();

    return 0;
}

预期输出:

答案在此

C++数据结构与算法(全部答案)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习8:详解生成对抗网络原理

目录 大纲 生成随机变量 可以伪随机生成均匀随机变量 随机变量表示为操作或过程的结果 逆变换方法 生成模型 我们试图生成非常复杂的随机变量…… …所以让我们使用神经网络的变换方法作为函数&#xff01; 生成匹配网络 培养生成模型 比较基于样本的两个概率分布 …

Delphi 11.3 FMX 多设备平台中使用 TGrid 实现类似 TDBGrid 的效果

Delphi Firemonkey 中 TDBGrid 这个控件已经没有了。如何实现类似这个效果呢。其实可以用TGrid 来实现。以下用 11.3 来讲解。 查询里面用到的 connection 和 query 等控件那些一般的数据库用法&#xff0c;就不做过多描述了。请参考其他资料。 方法一.通过界面配置来实现 在…

DWA算法学习

一、DWA概念  DWA(动态窗口法)属于局部路径规划方法&#xff0c;为ROS中主要采用的方法。其原理主要是在速度空间&#xff08;v,w&#xff09;中采样多组速度&#xff0c;并模拟这些速度在一定时间内的运动轨迹&#xff0c;再通过一个评价函数对这些轨迹打分&#xff0c;最优的…

【conda install】网络慢导致报错CondaHTTPError: HTTP 000 CONNECTION FAILED for url

⭐⭐问题&#xff1a; 部署安装环境经常会出现由于网络慢问题&#xff0c;导致conda安装不了库&#xff0c;报错如下&#xff1a; Solving environment: failedCondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/…

Python钢筋混凝土结构计算.pdf-已知弯矩确定混凝土梁截面尺寸

计算原理 确定混凝土梁截面的合理尺寸通常需要考虑弯矩、受力要求和约束条件等多个因素。以下是一种常见的计算公式&#xff0c;用于基于已知弯矩确定混凝土梁截面的合理尺寸&#xff1a; 请注意&#xff0c;以上公式仅提供了一种常见的计算方法&#xff0c;并且具体的规范和设…

[halcon] 局部图片保存 gen_circle 和 gen_rectangle2 对比 这怕不是bug吧

背景 我想实现一个功能&#xff0c;获取图片中瑕疵的位置&#xff0c;将瑕疵周边的一块区域抠图并保存。 上代码 一开始我代码这么写的&#xff1a; gen_circle (Rectangle, Row[i], Column[i], 256) reduce_domain(Image,Rectangle,GrayEllipse) crop_domain(GrayEllipse,…

mac清理磁盘空间软件有哪些 mac清理磁盘空间怎么清理

随着时间的推移&#xff0c;Mac电脑上的文件会越来越多&#xff0c;很快就会占满磁盘空间。这时候&#xff0c;我们需要一个好的Mac清理磁盘空间软件来释放空间&#xff0c;保持电脑的良好性能。那么&#xff0c;mac清理磁盘空间软件有哪些呢&#xff1f;接下来&#xff0c;我将…

Skip Connection——提高深度神经网络性能的利器

可以参考一下这篇知乎所讲 https://zhuanlan.zhihu.com/p/457590578 长跳跃连接用于将信息从编码器传播到解码器&#xff0c;以恢复在下采样期间丢失的信息

P5-P8都需要掌握哪些技术

P5级别技术栈 职级:中级工程师 薪资:年薪20万-40万 要求:扎实的Java基础&#xff0c;对常见的设计模式与数据结构算法有颇多研究&#xff0c;熟悉常见的开发规范。 P6级别技术栈 职级:高级/资深工程师 薪资:年薪40万-60万 要求:熟悉各种技术中间件的使用与优化&#…

腾讯云-对象存储服务(COS)的使用总结-JavaScript篇

简介 对象存储&#xff08;Cloud Object Storage&#xff0c;COS&#xff09;是腾讯云提供的一种存储海量文件的分布式存储服务&#xff0c;具有高扩展性、低成本、可靠安全等优点。通过控制台、API、SDK 和工具等多样化方式&#xff0c;用户可简单、快速地接入 COS&#xff0…

机器学习:异常检测实战

文章目录 Anomaly Detection目录任务介绍数据集方法评估Baseline报告报告评价标准 Anomaly Detection 目录 任务介绍 无监督的异常检测 数据集 方法 autoencode 是否能够还原出原始类型图片&#xff0c;基于重构loss来判断是否正常 重构误差当作异常分数 评估 采用ROC和AUC…

Gitlab创建一个空项目

1. 创建项目 Project slug是访问地址的后缀&#xff0c;跟前边的ProjectUrl拼在一起&#xff0c;就是此项目的首页地址&#xff1b; Visibility Level选择默认私有即可&#xff0c;选择内部或者公开&#xff0c;就会暴露代码。 勾选Readme选项&#xff0c;这样项目内默认会带…

探索OLED透明屏的优缺点:引领科技未来的革命性突破

OLED透明屏作为一项革命性的创新技术&#xff0c;其令人惊叹的透明度和柔性性能引起了全球范围内的关注。 然而&#xff0c;了解OLED透明屏的优缺点对于我们全面认识其在科技未来中的地位至关重要。 今天&#xff0c;尼伽将深入探讨OLED透明屏的优势和限制&#xff0c;并借助…

【重要】【转载】NOR Flash芯片内执行(XIP)

为什么程序不能直接在nandflash上执行&#xff1f;出于这个疑惑带来了这篇博文&#xff0c;是我在网上找了很多资料后总结的&#xff0c;假如有误&#xff0c;希望马上指出来&#xff0c;免得我误人子弟。谢谢&#xff01; 首先认识下nandflash和norflash&#xff1a; NOR Flas…

Python学习 -- 异常分类

在编写Python代码时&#xff0c;异常处理是至关重要的一部分&#xff0c;它能够帮助我们更好地应对意外情况&#xff0c;提高程序的健壮性。本文将详细介绍Python中常见的异常类型&#xff0c;包括AttributeError、FileNotFoundError、IndexError、KeyError、NameError、TypeEr…

第十七课:利用 Setup Factory 制作 Qt 软件安装包

功能描述&#xff1a;详细介绍如何利用 Setup Factory 制作 Qt 软件安装包&#xff0c;从 Setup Factory 软件下载、安装&#xff0c;到如何利用 Setup Factory 制作软件安装包&#xff0c;手把手教你将 Qt 应用程序制作成具有安装向导的安装包。 一、Setup Factory 简介 Setu…

Java基础 数据结构一【栈、队列】

什么是数据结构 数据结构是计算机科学中的一个重要概念&#xff0c;用于组织和存储数据以便有效地进行访问、操作和管理。它涉及了如何在计算机内存中组织数据&#xff0c;以便于在不同操作中进行查找、插入、删除等操作 数据结构可以看作是一种数据的组织方式&#xff0c;不…

脚本掌控,Linux上实现Spring Boot(JAR包)开机自启

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; 脚本掌控&#xff0c;Linux上实现Spring Boot&#xff08;JAR包&#x…

TCP/UDP原理

文章目录 一、端口1. 端口的定义和作用2.服务端和客户端的区别3.常见的知名端口号有 二、TCP的原理1.TCP头部封装格式2.TCP可靠性机制三次握手确认机制四次挥手RST结束连接窗口机制 3.完整性校验4.TCP特征5.TCP的适用场景 三、UDP的原理1.UDP头部封装格式2.UDP特征3.UDP的适用场…

编写c语言程序调用openssl编译出的动态链接库

文章目录 一、编译生成链接库二、示例一&#xff1a;调用RAND_bytes函数三、示例二&#xff1a;调用SHA256 一、编译生成链接库 下载安装openssl并编译生成链接库的过程在我的另一篇文章中已经详细说明了&#xff1a;Ubuntu中安装OpenSSL 此外&#xff0c;我们还需要提前了解…