1. 动态数组的优点
与普通的数组(静态数组)不同,动态数组根据需要随时改变大小,但是静态数组库一旦定义,大小就不可改变了
2.动态数组库的接口(代码放在DynamicArray.h中),主要包括结构体的声明和操作动态数组的函数的声明
| #ifndef SEVENTH_CPP_PROJECT_CLASS_INHERITANCE_DYNAMICARRAY_H |
| #define SEVENTH_CPP_PROJECT_CLASS_INHERITANCE_DYNAMICARRAY_H |
| struct DynamicArray; |
| typedef struct DynamicArray DArray; |
| typedef struct DynamicArray *PDArray; |
| |
| PDArray InitDArray(int count); |
| int GetLength(PDArray &p); |
| int* GetAddress(PDArray &p); |
| void InitElement(PDArray &p); |
| void TraverseDArray(PDArray &p); |
| void SwapElement(PDArray &p, int i, int j); |
| void BubbleSort(PDArray &p); |
| int BinarySearch(PDArray &p, int key); |
| void ResizeDArray(PDArray &p, int new_length); |
| void AppendElement(PDArray &p, int ele_count); |
| void AppendIdxElement(PDArray &p, int idx, int key); |
| void DeleteElement(PDArray &p, int ele_count); |
| void DeleteIdxElement(PDArray &p, int idx); |
| |
| #endif |
3.动态数组库的实现(代码放在DynamicArray.cpp中),主要包括结构体的定义和函数的实现
| #include <iostream> |
| #include "DynamicArray.h" |
| |
| using namespace std; |
| struct DynamicArray { |
| int count; |
| int* data; |
| }; |
| |
| PDArray InitDArray(int count) { |
| |
| auto p = new DArray; |
| p->count = count; |
| p->data = new int[count]; |
| return p; |
| } |
| |
| int GetLength(PDArray &p) { |
| |
| return p->count; |
| } |
| |
| int* GetAddress(PDArray &p) { |
| |
| return p->data; |
| } |
| |
| void InitElement(PDArray &p) { |
| |
| int length = GetLength(p); |
| int* addr = p->data; |
| cout << "Please input "<<length<<" integers: "; |
| for (int i = 0; i < length; i++) { |
| |
| cin >> addr[i]; |
| } |
| } |
| |
| void TraverseDArray(PDArray &p) { |
| |
| int* addr = p->data; |
| for (int i = 0; i < GetLength(p); i++) { |
| cout << addr[i] << " "; |
| } |
| cout << endl; |
| } |
| |
| void SwapElement(PDArray &p, int i, int j) { |
| |
| int length = GetLength(p); |
| if (i >= length || j >= length || i < 0 || j < 0) { |
| |
| exit(1); |
| } else { |
| int* addr = p->data; |
| int temp = addr[i]; |
| addr[i] = addr[j]; |
| addr[j] = temp; |
| } |
| } |
| |
| void BubbleSort(PDArray &p) { |
| |
| |
| |
| int* addr = p->data; |
| int n = GetLength(p); |
| |
| |
| int last = n-1; |
| int end; |
| for (int i = 0; i < n-1; i++) { |
| end = last; |
| bool flag = false; |
| for (int j = 0; j < end; j++) { |
| if (addr[j] > addr[j+1]) { |
| SwapElement(p, j, j+1); |
| flag = true; |
| last = j; |
| } |
| } |
| |
| if(!flag) |
| break; |
| } |
| } |
| |
| int BinarySearch(PDArray &p, int key) { |
| |
| |
| int low = 0, high = GetLength(p), idx = -1, mid; |
| int* addr = p->data; |
| while(low <= high) { |
| mid = (low + high)/2; |
| if (addr[mid] == key) { |
| idx = mid; |
| break; |
| } else if (addr[mid] > key) { |
| high = mid - 1; |
| } else if (addr[mid] < key) { |
| low = mid + 1; |
| } |
| } |
| return idx; |
| } |
| |
| void ResizeDArray(PDArray &p, int new_length) { |
| |
| |
| int length = p->count; |
| int* temp = new int[new_length]; |
| int min = new_length < length ? new_length : length; |
| for (int i = 0; i < min; i++) { |
| |
| temp[i] = p->data[i]; |
| } |
| if(new_length > length) { |
| |
| cout << "Please input " << new_length - length << " integers: "; |
| for (int i = length; i < new_length; i++) { |
| cin >> temp[i]; |
| } |
| } |
| |
| delete[] p->data; |
| p->count = new_length; |
| p->data = temp; |
| } |
| |
| void AppendElement(PDArray &p, int ele_count) { |
| |
| |
| ResizeDArray(p, GetLength(p) + ele_count); |
| } |
| |
| void AppendIdxElement(PDArray &p, int idx, int key) { |
| |
| int length = p->count; |
| if (idx < 0 || idx > length) exit(1); |
| int* temp = new int[length+1]; |
| for (int i = 0; i < key; i++) { |
| temp[i] = p->data[i]; |
| } |
| temp[idx] = key; |
| for (int j = idx; j < length; j ++) { |
| temp[j+1] = p->data[j]; |
| } |
| |
| delete[] p->data; |
| p->count = length + 1; |
| p->data = temp; |
| } |
| |
| void DeleteElement(PDArray &p, int ele_count) { |
| |
| |
| int length = GetLength(p); |
| if (ele_count > length) exit(1); |
| ResizeDArray(p, length - ele_count); |
| } |
| |
| void DeleteIdxElement(PDArray &p, int idx) { |
| |
| int length = GetLength(p); |
| int* temp = new int[length-1]; |
| if (idx < 0 || idx >= length) exit(1); |
| for (int i = 0; i < idx; i++) { |
| temp[i] = p->data[i]; |
| } |
| for (int i = idx; i < length - 1; i++) { |
| temp[i] = p->data[i+1]; |
| } |
| |
| delete[] p->data; |
| p->data = temp; |
| p->count = length - 1; |
| } |
4.动态数组库的使用与测试(代码放在main.cpp中)
| #include <iostream> |
| #include <string> |
| #include "DynamicArray.h" |
| |
| using namespace std; |
| |
| int main() { |
| |
| string s; |
| cout << "Please input a string: "; |
| getline(cin, s, '\n'); |
| cout << "Your input string is : " << s << endl; |
| |
| |
| |
| |
| PDArray p = InitDArray(5); |
| cout << "p = "<<p<<"" << endl; |
| |
| |
| |
| |
| int length = GetLength(p); |
| cout << length << endl; |
| |
| |
| int* addr = GetAddress(p); |
| cout << "The base address of array is: " << addr << endl; |
| |
| |
| InitElement(p); |
| |
| |
| TraverseDArray(p); |
| |
| |
| SwapElement(p, 0, 2); |
| TraverseDArray(p); |
| |
| |
| BubbleSort(p); |
| TraverseDArray(p); |
| |
| |
| int idx = BinarySearch(p, 3); |
| cout << "idx = "<<idx<<"" << endl; |
| |
| |
| cout << "Before resize array, p = "<<p<<"" << endl; |
| cout << "Before resize array, p->data = "<<GetAddress(p)<<"" << endl; |
| ResizeDArray(p, 3); |
| cout << "After resize array, p = "<<p<<"" << endl; |
| cout << "After resize array, p->data = "<<GetAddress(p)<<"" << endl; |
| TraverseDArray(p); |
| |
| |
| AppendElement(p, 3); |
| TraverseDArray(p); |
| cout << "p->data = "<<GetAddress(p)<<"" << endl; |
| |
| |
| AppendIdxElement(p, 2, 9); |
| TraverseDArray(p); |
| cout << "p->data = "<<GetAddress(p)<<"" << endl; |
| |
| |
| DeleteElement(p, 2); |
| TraverseDArray(p); |
| cout << "p->data = "<<GetAddress(p)<<"" << endl; |
| |
| |
| DeleteIdxElement(p, 3); |
| TraverseDArray(p); |
| cout << "p->data = "<<GetAddress(p)<<"" << endl; |
| return 0; |
| } |
| |
5.结构体在DynamicArray.h头文件中声明,在DynamicArray.cpp中定义的原因
1.主要是为了数据的封装和信息隐藏,这样做之后,在main.cpp中,只能通过一个指向结构体的指针和动态数组库提供的接口来访问这个函数。
2.这是因为我们在main.cpp 中include "DynamicArray.h"了,但是头文件中并没有结构体的定义,只有结构体的声明
3.这种思想和类中的private成员一样,类的外部不可访问这些private成员,但是类的内部可以
4.在main函数中,不能显示的访问结构体的成员,比如:
| |
| |
| PDArray p = InitDArry(10); |
| int count = p->count; |
| int count = GetLength(p); |
5.这种做法的最大好处就是信息隐藏。
作为一个库的使用者,库的提供者会为你提供头文件(接口),但是一般不会提供库的实现代码,而是直接提供库编译号的二进制代码。
如果提供了源代码,可能一个小小的修改,都会造成整个库的崩溃!甚至带来不可预期的危害。
只提供头文件(接口),保护了整个库的正常运作,试想一下,如果结构体定义在头文件中,你随意改一下,整个库就不能用了。
所以这种思想就是在头文件中提供的是纯粹的接口,告诉库的使用者能干啥而不是告诉你你可以修改啥。
6.如果某个库不让修改,还实现不了库使用者的需要,那么赶紧这个库就是个垃圾库!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)