当前位置: 首页 > news >正文

《C++程序设计》笔记p7

宏和模板

写一个宏 SWAP(a, b) 交换两个变量的值。

区别:

  • 宏只是源码级别的替换,不进行类型检查。
  • 模板进行类型检查,必要时报错,更安全。

函数模板

作用:

函数模板是用来编写与类型无关的通用函数。

定义的语法

template <typename 类型名1, typename 类型名2,...>
返回值 函数名(形参列表) {
}
函数模板使用的
函数模板名<实际类型>(实参列表)

说明:

  • 类型名常用T 开头,如:T 、 T1 、T2
  • 模板是声明不占用存储空间,一般写在头文件中。
  • 在使用函数模板时,C++会在编译阶段自动生成对应的函数代码。
  • 关键字 typename 可以使用 关键字 class 替换(class 是早期版本C++使用的关键字,新版本的建议使用 typename
  • 在使用函数模板是,如果调用时不指定模版类型,编译器会根据实参类型自动尝试推导模板的类型。
  • 一个 template <> 类型声明只对一个模版函数有效。

示例

/* 
#define SWAP(a, b) { \auto tmp = a; \a = b; \b = tmp; \
}#define MYSWAP(T) \
void myswap(T &a, T & b) { \auto tmp = a; \a = b; \b = tmp; \
}
MYSWAP(int)
MYSWAP(DynamicArray)
MYSWAP(double)
*/template <typename T>
void myswap(T &a, T & b) {auto tmp = a;a = b;b = tmp;
}int main(int argc, char * argv[]) {DynamicArray d1;DynamicArray d2;for (int i = 10; i <= 50; i+= 10)d1.push_back(i);d2.push_back(100);d2.push_back(200);cout << "d1:" << d1 << endl;cout << "d2:" << d2 << endl;int x = 100;int y = 200;myswap<int>(x, y);cout << "x:" << x << endl;cout << "y:" << y << endl;myswap<DynamicArray>(d1, d2);cout << "d1:" << d1 << endl;cout << "d2:" << d2 << endl;double x1 = 3.14;double x2 = 1.8;myswap<double>(x1, x2);cout << "x1:" << x1 << endl;cout << "x2:" << x2 << endl;return 0;
}

示例:

修改冒泡排序的算法,将其修改为函数模板,使其能对 int 类型的数组,double 类型的数组,甚至动态数组DynamicArray 进行排序。

参考代码

#include <stdio.h>
#include <iostream>using namespace std;class RangeError{public:RangeError(int i): error(i) {}int error;
};class DynamicArray {public:// 初始化动态数组DynamicArray():data(NULL), count(0), max_count(5) {}DynamicArray(const DynamicArray&src):data(NULL), count(src.count), max_count(src.max_count) {if (src.data) { // 如果src有数据才分配内存data = new int[max_count];}// 复制数据for (int i = 0; i < count; i++) {data[i] = src.data[i];}}DynamicArray & operator = (const DynamicArray&src) {if (NULL == src.data) { // src为空列表count = src.count; // count值为0return *this;}// src的数据个数少于this的数据个数if (src.count <= max_count) {count = src.count;for (int i = 0; i < count; i++) {data[i] = src.data[i];}return *this;}// src的数据个数多于 this的数据个数if (data)delete [] data;data = new int[src.max_count];count = src.count;max_count = src.max_count;for (int i = 0; i < count; i++) {data[i] = src.data[i];}return *this;}~DynamicArray() {if (data) {delete [] data;}}// 2.  添加数据void push_back(const int & x){// 需要重新分配内存if (data == NULL)  {// 一定要分配内存resizeTo(max_count);} else if (count >= max_count) { // 需要扩容resizeTo(max_count * 2);}data[count] = x;count ++;}// 4.  修改第 i 个学生的成绩。pos 从 0 开始int & operator[](int index) {if (index < 0 || index >= count)throw RangeError(index);return data[index];}// 5.  删除某个位置的学生成绩。bool removeAt(int index) {if (index < 0 || index > count)return false;// throw RangeError(index);for (int i = index; i < count-1; i++) {data[i] = data[i+1];}count--;return true;}DynamicArray operator+(const DynamicArray &r) {// 效率优化版DynamicArray tmp;tmp.max_count = count + r.count + 5;tmp.count = count + r.count;tmp.data = new int[tmp.max_count];// 复制每一个整数值int i;for (i = 0; i < count; i++) {//复制this数据tmp.data[i] = data[i];}//复制r的数据for (int j = 0; j < r.count; j++) {tmp.data[i+j] = r.data[j];}// 简化版// DynamicArray tmp(*this);// for (int i = 0; i < r.count; i++) {//     tmp.push_back(r[i]);// }return tmp;}DynamicArray &operator+=(const DynamicArray &r) {if (count + r.count > max_count) {// 从新分配内存resizeTo(max_count + r.max_count);}// 开始复制for (int i = 0; i < r.count; i++) {data[count + i] = r.data[i];}count += r.count;// *this = *this + r;return *this;}int size(void) { // 返回大小return count;}void * get_data(void) { // 返回数据的起始地址return data;}bool empty(void) { // 返回数据是否为空return count == 0;}private:// 扩容到指定的容量volumn, 成共扩容返回true,// 否则返回 false;bool resizeTo(int volumn){// 需要重新分配内存int * temp;if (data == NULL)  {// 一定要分配内存data = new int[volumn];return true;}if (count > volumn)  // 新容量小于旧容量return false;if (max_count >= volumn)return true;// 真正扩容temp = new int[volumn];for (int i = 0; i < count; i++) {temp[i] = data[i]; // 复制旧数据}delete [] data;data = temp;max_count = volumn;return true;}private:int * data;  // 用来保存学生的成绩数据的指针int count; // 用来记录学生的个数。int max_count;  // 用来记录当前内存能存储的最大数据friend ostream & operator<<(ostream &o, DynamicArray da);
};ostream & operator<<(ostream &o, DynamicArray da) {o << "[";for (int i = 0; i < da.count; i++) {o << da.data[i];if ( i < da.count -1)o << ", ";}o << "]";return o;
}// 冒泡排序(基础算法)
template <typename T>
void bubble_sort(T *arr, int data_count) {
// void bubble_sort(T &arr, int data_count) {// i 表示此处循环将最大数放入的位置。for (int i = data_count - 1; i > 0; i--) {// j 表示正在准备交换的前一个数据的位置。for (int j = 0; j < i; j++) {if (arr[j] > arr[j+1]) {// 成立则交换auto temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}
}template<typename T>
// void print_array(T &arr, int data_count) {
void print_array(T *arr, int data_count) {for (int i = 0; i < data_count; i++) {// printf("%d ", arr[i]);cout << arr[i] << ' ';}printf("\n");
}int main(int argc, char * argv[]) {int data[100] = {6, 8, 1, 9, 3, 7, 5};// bubble_sort<int[100]>(data, 7);bubble_sort(data, 7);print_array(data, 7);double data2[] = {3.14, 2.9, 3, 90.2, 7.8};// bubble_sort<double[5]>(data2, 5);bubble_sort(data2, 5);print_array(data2, 5);DynamicArray d1;d1.push_back(6);d1.push_back(8);d1.push_back(1);d1.push_back(9);bubble_sort((int*)d1.get_data(), d1.size());print_array((int*)d1.get_data(), d1.size());
//  	print_array(d1, d1.size());printf("程序退出\n");
}

升级后,可以升序排序和降序排序的冒泡排序版本

// 排序 
#include <stdio.h>
#include <iostream>using namespace std;class RangeError{public:RangeError(int i): error(i) {}int error;
};class DynamicArray {public:// 初始化动态数组DynamicArray():data(NULL), count(0), max_count(5) {}DynamicArray(const DynamicArray&src):data(NULL), count(src.count), max_count(src.max_count) {if (src.data) { // 如果src有数据才分配内存data = new int[max_count];}// 复制数据for (int i = 0; i < count; i++) {data[i] = src.data[i];}}DynamicArray & operator = (const DynamicArray&src) {if (NULL == src.data) { // src为空列表count = src.count; // count值为0return *this;}// src的数据个数少于this的数据个数if (src.count <= max_count) {count = src.count;for (int i = 0; i < count; i++) {data[i] = src.data[i];}return *this;}// src的数据个数多于 this的数据个数if (data)delete [] data;data = new int[src.max_count];count = src.count;max_count = src.max_count;for (int i = 0; i < count; i++) {data[i] = src.data[i];}return *this;}~DynamicArray() {if (data) {delete [] data;}}// 2.  添加数据void push_back(const int & x){// 需要重新分配内存if (data == NULL)  {// 一定要分配内存resizeTo(max_count);} else if (count >= max_count) { // 需要扩容resizeTo(max_count * 2);}data[count] = x;count ++;}// 4.  修改第 i 个学生的成绩。pos 从 0 开始int & operator[](int index) {if (index < 0 || index >= count)throw RangeError(index);return data[index];}// 5.  删除某个位置的学生成绩。bool removeAt(int index) {if (index < 0 || index > count)return false;// throw RangeError(index);for (int i = index; i < count-1; i++) {data[i] = data[i+1];}count--;return true;}DynamicArray operator+(const DynamicArray &r) {// 效率优化版DynamicArray tmp;tmp.max_count = count + r.count + 5;tmp.count = count + r.count;tmp.data = new int[tmp.max_count];// 复制每一个整数值int i;for (i = 0; i < count; i++) {//复制this数据tmp.data[i] = data[i];}//复制r的数据for (int j = 0; j < r.count; j++) {tmp.data[i+j] = r.data[j];}// 简化版// DynamicArray tmp(*this);// for (int i = 0; i < r.count; i++) {//     tmp.push_back(r[i]);// }return tmp;}DynamicArray &operator+=(const DynamicArray &r) {if (count + r.count > max_count) {// 从新分配内存resizeTo(max_count + r.max_count);}// 开始复制for (int i = 0; i < r.count; i++) {data[count + i] = r.data[i];}count += r.count;// *this = *this + r;return *this;}int size(void) { // 返回大小return count;}void * get_data(void) { // 返回数据的起始地址return data;}bool empty(void) { // 返回数据是否为空return count == 0;}private:// 扩容到指定的容量volumn, 成共扩容返回true,// 否则返回 false;bool resizeTo(int volumn){// 需要重新分配内存int * temp;if (data == NULL)  {// 一定要分配内存data = new int[volumn];return true;}if (count > volumn)  // 新容量小于旧容量return false;if (max_count >= volumn)return true;// 真正扩容temp = new int[volumn];for (int i = 0; i < count; i++) {temp[i] = data[i]; // 复制旧数据}delete [] data;data = temp;max_count = volumn;return true;}private:int * data;  // 用来保存学生的成绩数据的指针int count; // 用来记录学生的个数。int max_count;  // 用来记录当前内存能存储的最大数据friend ostream & operator<<(ostream &o, DynamicArray da);
};ostream & operator<<(ostream &o, DynamicArray da) {o << "[";for (int i = 0; i < da.count; i++) {o << da.data[i];if ( i < da.count -1)o << ", ";}o << "]";return o;
}template <typename N>
void myswap(N & a, N &b) {auto temp = a;a = b;b = temp;
}// 冒泡排序(基础算法)
template <typename T>
void bubble_sort(T *arr, int data_count, bool (*comp)(T &, T &) = NULL) {
// void bubble_sort(T &arr, int data_count) {// i 表示此处循环将最大数放入的位置。for (int i = data_count - 1; i > 0; i--) {// j 表示正在准备交换的前一个数据的位置。for (int j = 0; j < i; j++) {if (comp) {if (comp(arr[j], arr[j+1])) {myswap<T>(arr[j], arr[j+1]);}} else {if (arr[j] > arr[j+1]) {myswap<T>(arr[j], arr[j+1]);}}}}
}template<typename T>
// void print_array(T &arr, int data_count) {
void print_array(T *arr, int data_count) {for (int i = 0; i < data_count; i++) {// printf("%d ", arr[i]);cout << arr[i] << ' ';}printf("\n");
}// 前面比后面的大就返回真(升序排序)
bool comp_int_asc(int & front, int & last) {return front > last;
}
// 降序排序)
bool comp_int_desc(int & front, int & last) {return front < last;
}
int main(int argc, char * argv[]) {int data[100] = {6, 8, 1, 9, 3, 7, 5};// bubble_sort<int[100]>(data, 7);bubble_sort(data, 7, &comp_int_desc);print_array(data, 7);double data2[] = {3.14, 2.9, 3, 90.2, 7.8};// bubble_sort<double[5]>(data2, 5);bubble_sort(data2, 5);print_array(data2, 5);DynamicArray d1;d1.push_back(6);d1.push_back(8);d1.push_back(1);d1.push_back(9);bubble_sort((int*)d1.get_data(), d1.size());print_array((int*)d1.get_data(), d1.size());
//  	print_array(d1, d1.size());printf("程序退出\n");
}

类模板

作用:编写于类型无关的通用类,实现与类型无关代码的复用。

类模板的语法

template <typename 类型参数名1[=缺省类型1], typename 类型参数名2[=缺省类型2],...>
class 类名 {... 类的实现
};template <typename ...>
class 类名2 {
}

说明:

  1. template 类模板是声明,不是实现,一般放在头文件中(不会生成实际类)。
  2. 一个template 关键字声明只对一个类或一个函数有效。
  3. typename 可以用class 代替(新版本建议使用typename).

类模板创建类的语法

类模板名<真实存在的类型名> 变量1, 变量2;

示例:

#include <iostream>
// #include <stdio.h>
// #include <stdlib.h>using namespace std;class RangeError{public:RangeError(int i): error(i) {}int error;
};template<typename T=int>
class DynamicArray {public:// 初始化动态数组DynamicArray():data(NULL), count(0), max_count(5) {}DynamicArray(const DynamicArray&src):data(NULL), count(src.count), max_count(src.max_count) {if (src.data) { // 如果src有数据才分配内存data = new T/*int*/[max_count];}// 复制数据for (int i = 0; i < count; i++) {data[i] = src.data[i];}}DynamicArray & operator = (const DynamicArray&src) {if (NULL == src.data) { // src为空列表count = src.count; // count值为0return *this;}// src的数据个数少于this的数据个数if (src.count <= max_count) {count = src.count;for (int i = 0; i < count; i++) {data[i] = src.data[i];}return *this;}// src的数据个数多于 this的数据个数if (data)delete [] data;data = new T/*int*/[src.max_count];count = src.count;max_count = src.max_count;for (int i = 0; i < count; i++) {data[i] = src.data[i];}return *this;}~DynamicArray() {if (data) {delete [] data;}}// 2.  添加数据void push_back(const T/*int*/ & x){// 需要重新分配内存if (data == NULL)  {// 一定要分配内存resizeTo(max_count);} else if (count >= max_count) { // 需要扩容resizeTo(max_count * 2);}data[count] = x;count ++;}// 4.  修改第 i 个学生的成绩。pos 从 0 开始T/*int*/ & operator[](int index) {if (index < 0 || index >= count)throw RangeError(index);return data[index];}// 5.  删除某个位置的学生成绩。bool removeAt(int index) {if (index < 0 || index > count)return false;// throw RangeError(index);for (int i = index; i < count-1; i++) {data[i] = data[i+1];}count--;return true;}// 7.  在 pos 之前的位置插入学生的成绩bool insertAt(int pos, T/*int*/ score){}DynamicArray operator+(const DynamicArray &r) {// 效率优化版DynamicArray tmp;tmp.max_count = count + r.count + 5;tmp.count = count + r.count;tmp.data = new T/*int*/ [tmp.max_count];// 复制每一个整数值int i;for (i = 0; i < count; i++) {//复制this数据tmp.data[i] = data[i];}//复制r的数据for (int j = 0; j < r.count; j++) {tmp.data[i+j] = r.data[j];}// 简化版// DynamicArray tmp(*this);// for (int i = 0; i < r.count; i++) {//     tmp.push_back(r[i]);// }return tmp;}DynamicArray &operator+=(const DynamicArray &r) {if (data == NULL) {resizeTo(max_count + r.max_count);}if (count + r.count > max_count) {// 从新分配内存resizeTo(max_count + r.max_count);}// 开始复制for (int i = 0; i < r.count; i++) {data[count + i] = r.data[i];}count += r.count;// *this = *this + r;return *this;}//模板内声明int size(void);// int size(void) { // 返回大小//     return count;// }void * get_data(void) { // 返回数据的起始地址return data;}bool empty(void) { // 返回数据是否为空return count == 0;}private:// 扩容到指定的容量volumn, 成共扩容返回true,// 否则返回 false;bool resizeTo(int volumn){// 需要重新分配内存T * temp;if (data == NULL)  {// 一定要分配内存data = new T/*int*/[volumn];max_count = volumn;return true;}if (count > volumn)  // 新容量小于旧容量return false;if (max_count >= volumn)return true;// 真正扩容temp = new T/*int*/[volumn];for (int i = 0; i < count; i++) {temp[i] = data[i]; // 复制旧数据}delete [] data;data = temp;max_count = volumn;return true;}private:T * data;  // 用来数据的指针int count; // 用来记录个数。int max_count;  // 用来记录当前内存能存储的最大数据template<typename T1>friend ostream & operator<<(ostream &o, DynamicArray<T1> da);
};template <typename T>
int DynamicArray<T>::size(void) { // 返回大小return count;
}template<typename T1>
ostream & operator<<(ostream &o, DynamicArray<T1> da) {o << "[";for (int i = 0; i < da.count; i++) {o << da.data[i];if ( i < da.count -1) o << ", ";}o << "]";return o;
}
int main(int argc, char * argv[]) {// DynamicArray<Shape*> shapes;DynamicArray<int> d1;DynamicArray<int> d3 = d1;for (int i = 10; i <= 50; i+= 10)d1.push_back(i);d3 += d1;DynamicArray<double> d2;cout << "d1:" << d1 << endl;cout << "d2:" << d2 << endl;d2.push_back(10.1);d2.push_back(20.2);cout << "d1:" << d1 << endl;cout << "d2:" << d2 << endl;cout << "d2.size(): " << d2.size() << endl;return 0;
}

函数模板和类模板是泛型算法的基础。

泛型算法

泛型算法是一种编程范式,核心思想是编写与类型无关的通用代码,让算法和数据结构等能够适用于不同的数据类型。

核心思想:

一次编写,多次使用。

模版的参数语法:

模版的参数内不仅可以有模版类型的定义,还可以有变量的定义。

template <typename T, int N>
class 模板名{...
};

示例代码

#include <iostream>
// #include <stdio.h>
// #include <stdlib.h>using namespace std;template<typename T, int N>
class StaticArray{public:T data[N];
};int main(int argc, char * argv[]) {StaticArray<int, 100> a1;return 0;
}

标准模板库(STL)

标准模板库(Standard Template Library) 是C++的基础库,它包含在 std名字空间中。

标准模板库核心组成

  • 容器(Container)
  • 算法(Algorithms)
  • 迭代器(Iterators)

容器Container

  • 动态数组 vector
  • 定长数组 array
  • 双端队列 deque
  • 映射 map
  • 无序映射 unordered_map
  • 集合 set
  • 无序集合unordered_set

vector 的常用成员函数

.push_back(const T& value) 向后追加
.pop_back() 删除尾部数据
.at( size_type pos )返回某位置数据的引用(做边界检测)
.operator[]( size_type pos ) 返回某位置数据的引用
.front() 返回第一个数据
.back()  返回最后一个数据
.clear() 清空数组。
.resize(size_type count, const value_type& value),将数组变为指定的长度,如果 count <= .size() 则删除后面的数据,如果count > .size(),多余的位置填充 value,

示例代码:

#include <iostream>
#include <vector>using namespace std;
class Student {public:Student(const string &n, int a, int s):name(n),age(a),score(s){}bool operator<(const Student &other) const {return score < other.score;}string name;int age;int score;
};int main(int argc, char * argv[]) {vector<Student> v1 = {Student("张3", 18, 100)};vector<Student> v2 = {Student("李四", 19, 80)};// vector<int> v1 = {1, 2, 3};// vector<int> v2 = {100, 2, 3};cout << (v1 < v2) << endl;return 0;
}

迭代器

STL的容器类中都封装了迭代器类,用于操作容器类内的数据。

迭代器,可以理解成访问成员的指针。

作用:统一容器类的数据访问方法。便于范型编程。

.begin()  // 返回容器数据开始位置的迭代器,类型:iterator
.end()  // 返回容器数据结束位置的迭代器(最后一个元素的后面)
.rbegin()//返回反项迭代器的起始位置(最后一个元素),类型reverse_iterator
.rend() // 返回反项迭代器的结束位置(第一个元素的前一位置)。// 返回常迭代器
.cbegin()、.cend(): // 返回类型:const_iterator
.crbegin()、.crend(); // 返回类型:const_reverse_iterator

迭代器大概图示:

示例

#include <iostream>
#include <vector>
#include <chrono>using namespace std;int main(int argc, char * argv[]) {int buf[] = {11, 22, 33, 44, 55};int * begin;int * end;begin = &buf[0];end = &buf[5];int * it; // it 就是遍历数组 buf的迭代器;for (it = begin; it != end; ++it) {// *it *= 2;cout << *it << endl;}// 容器类的迭代器vector<int> myarr = {111, 222, 333, 444};for (vector<int>::iterator it=myarr.begin();it != myarr.end(); ++it) {cout << *it << endl;}const int * cit;  // 常迭代器for (cit = begin; cit != end; ++cit) {// *cit *= 2; // 报错cout << *cit << endl;}// for (vector<int>::const_iterator it=myarr.cbegin();for (auto it=myarr.cbegin();it != myarr.cend(); ++it) {// *it *= 2; // 报错cout << *it << endl;}//打印 444, 333, 222, 111for (vector<int>::reverse_iterator it = myarr.rbegin();it != myarr.rend(); ++it) {cout << *it << endl;}vector<int>::iterator myit = myarr.begin();cout << "第一个元素:" << *myit << endl;myit += 2;cout << "第三个元素:" << *myit << endl;return 0;
}

vector 的常用成员函数(用于插入和删除的方法)

// 在指定位置插入数据
iterator insert( const_iterator pos, const T& value );
// 在指定位置插入count 个相同值的数据
iterator insert( const_iterator pos,size_type count, const T& value );
// 删除指定位置的数据
iterator erase( iterator pos );
iterator erase( const_iterator pos );
// 删除指定范围内的数据(不包含last)
iterator erase( iterator first, iterator last );
iterator erase( const_iterator first, const_iterator last );

range_for 语句

用于遍历原生数组或含有.begin() 和 .end()成员函数并返回迭代器的可迭代的对象。

可迭代对象是指能用.begin() 和 .end() 成员函数 返回迭代器的对象。

语法:

for (类型 变量: 可迭代对象) {... 循环体.
}

示例:

for (int x: myarr) {...
}
// 等同于:
for (auto it = myarr.begin(); it != myarr.end(); ++it) {int x = *it;...
}

示例代码

#include <iostream>
#include <vector>using namespace std;
class Student {public:Student(const string &n, int a, int s):name(n),age(a),score(s){}bool operator<(const Student &other) const {return score < other.score;}string name;int age;int score;
};int main(int argc, char * argv[]) {vector<Student> v1 = {Student("张3", 18, 100),Student("李4", 19, 80),Student("王5", 17, 70),};// 遍历容器对象for (const Student &s:v1) {cout << "姓名:" << s.name << ",年龄:" << s.age << endl;}// 遍历原生数组int a1[] = {111, 222, 333, 444};for (int value: a1) {cout << "value:" << value << endl;}return 0;
}

vector 内部还可以包含动态数组

示例代码:

#include <iostream>
#include <vector>using namespace std;
class Student {public:Student(const string &n, int a, int s):name(n),age(a),score(s){}bool operator<(const Student &other) const {return score < other.score;}string name;int age;int score;
};int main(int argc, char * argv[]) {vector<vector<Student>> school;return 0;
}

range_for 的原理(迭代器原理)

参考代码:

#include <iostream>
// #include <stdio.h>
// #include <stdlib.h>using namespace std;class RangeError{public:RangeError(int i): error(i) {}int error;
};class DynamicArray {public:class iterator {public:iterator(DynamicArray & d, int pos = 0): da(d), cur_pos(pos) {}bool operator!=(const iterator & r) const {return cur_pos != r.cur_pos;}iterator & operator++(void) {++cur_pos;return *this;}int & operator*(void) { // 解引用运算符重载return da[cur_pos];}int * operator->(void) {return &da[cur_pos];}private:DynamicArray & da; // 绑定迭代的动态数组int cur_pos;  // 使用记录迭代的位置};public:iterator begin() { // 返回开始的迭代器return iterator(*this);}iterator end() { // 返回结束位置后一个元素的迭代器return iterator(*this, count);}public:// 初始化动态数组DynamicArray():data(NULL), count(0), max_count(5) {}DynamicArray(const DynamicArray&src):data(NULL), count(src.count), max_count(src.max_count) {if (src.data) { // 如果src有数据才分配内存data = new int[max_count];}// 复制数据for (int i = 0; i < count; i++) {data[i] = src.data[i];}}DynamicArray & operator = (const DynamicArray&src) {if (NULL == src.data) { // src为空列表count = src.count; // count值为0return *this;}// src的数据个数少于this的数据个数if (src.count <= max_count) {count = src.count;for (int i = 0; i < count; i++) {data[i] = src.data[i];}return *this;}// src的数据个数多于 this的数据个数if (data)delete [] data;data = new int[src.max_count];count = src.count;max_count = src.max_count;for (int i = 0; i < count; i++) {data[i] = src.data[i];}return *this;}~DynamicArray() {if (data) {delete [] data;}}// 2.  添加数据void push_back(const int & x){// 需要重新分配内存if (data == NULL)  {// 一定要分配内存resizeTo(max_count);} else if (count >= max_count) { // 需要扩容resizeTo(max_count * 2);}data[count] = x;count ++;}// 4.  修改第 i 个学生的成绩。pos 从 0 开始int & operator[](int index) {if (index < 0 || index >= count)throw RangeError(index);return data[index];}// 5.  删除某个位置的学生成绩。bool removeAt(int index) {if (index < 0 || index > count)return false;// throw RangeError(index);for (int i = index; i < count-1; i++) {data[i] = data[i+1];}count--;return true;}DynamicArray operator+(const DynamicArray &r) {// 效率优化版DynamicArray tmp;tmp.max_count = count + r.count + 5;tmp.count = count + r.count;tmp.data = new int[tmp.max_count];// 复制每一个整数值int i;for (i = 0; i < count; i++) {//复制this数据tmp.data[i] = data[i];}//复制r的数据for (int j = 0; j < r.count; j++) {tmp.data[i+j] = r.data[j];}// 简化版// DynamicArray tmp(*this);// for (int i = 0; i < r.count; i++) {//     tmp.push_back(r[i]);// }return tmp;}DynamicArray &operator+=(const DynamicArray &r) {if (data == NULL) {resizeTo(max_count + r.max_count);}if (count + r.count > max_count) {// 从新分配内存resizeTo(max_count + r.max_count);}// 开始复制for (int i = 0; i < r.count; i++) {data[count + i] = r.data[i];}count += r.count;// *this = *this + r;return *this;}int size(void) { // 返回大小return count;}void * get_data(void) { // 返回数据的起始地址return data;}bool empty(void) { // 返回数据是否为空return count == 0;}private:// 扩容到指定的容量volumn, 成共扩容返回true,// 否则返回 false;bool resizeTo(int volumn){// 需要重新分配内存int * temp;if (data == NULL)  {// 一定要分配内存data = new int[volumn];return true;}if (count > volumn)  // 新容量小于旧容量return false;if (max_count >= volumn)return true;// 真正扩容temp = new int[volumn];for (int i = 0; i < count; i++) {temp[i] = data[i]; // 复制旧数据}delete [] data;data = temp;max_count = volumn;return true;}private:int * data;  // 用来保存学生的成绩数据的指针int count; // 用来记录学生的个数。int max_count;  // 用来记录当前内存能存储的最大数据friend ostream & operator<<(ostream &o, DynamicArray da);
};ostream & operator<<(ostream &o, DynamicArray da) {o << "[";for (int i = 0; i < da.count; i++) {o << da.data[i];if ( i < da.count -1) o << ", ";}o << "]";return o;
}
int main(int argc, char * argv[]) {DynamicArray d1;for (int i = 10; i <= 50; i+= 10)d1.push_back(i);// for (DynamicArray::iterator it = d1.begin(); //         it != d1.end(); ++it) {//     int & x = *it;//     cout << x << endl;// }for (auto & x: d1) {cout << x << endl;}return 0;
}

双向链表 list

头文件

#include <list>

名字空间: std

list 的常用方法

.size()  返回列表内数据的长度。empty() 返回链表内数据是否为空。
。max_size() 返回链表等容纳数据的最大容量(依赖系统和环境)。
。clear()  清空列表
.insert(iterator pos, const T & value) 插入数据.
.erase(iterator pos) 删除数据.
.push_back(const T & value) 在末尾插入数据.
.push_front(const T & value) 在头部插入数据.
.pop_back()  删除末尾数据.
.pop_front()  删除开头数据.

map 映射表和 unordered_map 无序映射表

特点

  • 以键值对的形式存储数据,根据键查找值的速度快
  • map 查找时间复杂度O(Log2n)O(Log_2^n)O(Log2n​),使用二叉排序树存储。
  • unordered_map查找时间复杂度O(1)O(1)O(1),使用哈希表存储。
  • map、unordered_map键不能重复。
  • multimap和 unordered_multimap 键可以重复。

map 常用的方法

.find( const Key& key ); 根据键查找,返回迭代器iterator,没找到 iterator == map.end()。

示例

#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <unordered_map>using namespace std;
class Student {public:Student(const string &n="", int a=0, int s=0):name(n),age(a),score(s){}bool operator<(const Student &other) const {return score < other.score;}string name;int age;int score;
};int main(int argc, char * argv[]) {//键(key)是字符串,表示姓名,值(value) 是整数类型表示年龄// std::map<string, int> m;unordered_map<string, int> m;m["weimingze"] = 35;m["zhang3"] = 18;m["li4"] = 19; // 插入数据(键值对);cout << "映射表的数据个数是:" << m.size() << endl;m["li4"] = 88;  // 修改(键对应的值);m.insert({string("wang5"), 12});cout << m["王五"] << endl;cout << "映射表的数据个数是:" << m.size() << endl;cout << "李四的年龄是:" << m["li4"] << endl;for (auto it = m.begin();it != m.end(); ++it) {cout << "键:" << it->first<< " 值:" << it->second << endl;}// for (auto & pair: m) {//     cout << "键:" << pair.first<< " 值:" << pair.second << endl;// }// map<int, Student> person;// person[100] = Student("张3", 18, 100);// cout << "person的数据个数:" << person.size() << endl;//     vector<Student> v1 = {
//         Student("张3", 18, 100),
//         Student("李4", 19, 80),
//         Student("王5", 17, 70),
//     };return 0;
}

集合set和无序集合unordered_set

特点:

  1. 数据不能重复,查找速度快。
  2. set 查找时间复杂度O(Log2n)O(Log_2^n)O(Log2n​),使用二叉排序树存储。
  3. unordered_set查找时间复杂度O(1)O(1)O(1),使用哈希表存储。
  4. set、unordered_set值不能重复。
  5. multiset和 unordered_multiset 值可以重复。

示例

#include <iostream>
#include <set>using namespace std;int main(int argc, char * argv[]) {std::set<string> s;  // 创建一个集合s.insert("zhang3"); // 插入数据s.insert("li4");s.insert("zhang3");s.insert("wang5");s.insert("li4");cout << s.size() << endl;  // 集合默认去重复return 0;
}
http://www.dtcms.com/a/407137.html

相关文章:

  • 住房城乡建设网站查询wordpress 标签选项卡
  • 服务器机械硬盘能支撑高并发流媒体吗?
  • 奇妙数字(GESP五级202412T1)C++题解
  • 网站建设需要多少技术有备案号的网站是公司的吗
  • vscode壁纸插件(无主题修改)
  • OpenLayers地图交互 -- 章节十一:拖拽文件交互详解
  • 做网站优化的协议书免费网页制作的网站
  • 吃的网站要怎么做的企业管理咨询与诊断实践报告
  • Mac系统,Docker的MySQL + 本地 Canal
  • 零基础学Docker(3)--图形化管理工具Portainer
  • 远控中,游戏与应用中心功能如何开启?适用于哪些场景?
  • 零基础学Docker(4)--Docker镜像原理
  • 商丘网站制作报价信赖赛憬科技手机设计软件哪个好
  • R语言 生物分析中 富集分析的可视化,特别是气泡图和条形图的作用和解读
  • 上海市虹口市容建设公司网站文件外链生成网站
  • 利用h5做网站的心得学校网站建设意义有哪些方面
  • 美食网站建设多少钱wordpress又拍云cdn伪静态
  • 吴恩达d1
  • 第26讲 无监督机器学习
  • 【机器学习】我如何解释线性回归(欢迎指正讨论)
  • 申请的网站怎么建设广告公司加盟代理哪家好
  • STM32F4+RT-Thread IWDG 看门狗 开发实战:从驱动编写到“喂狗、超时复位”指南
  • 视频网站后台模板电影网站html代码
  • 从“黄金公式“到AI内容矩阵:快消品牌如何实现转化率8倍增长
  • Magick.NET库测试
  • 八、OpenCV中的常见滤波方式
  • ReAct与PlanReAct的定义及区别
  • 网站 廉政建设 板块中装建设官网
  • 63.[前端开发-Vue3]Day05-非父子通信-声明周期-refs-混合-额外补充
  • 用CodeBuddy Code CLI构建现代化Vue待办事项应用:从零到部署的完整实战