线性表——数组描述
1 数据对象和数据结构
数据对象和数据结构是在算法和程序设计中非常重要的概念。数据对象是我们希望操作和处理的实体,而数据结构则是数据对象之间的关系和组织方式。
2 线性表数据结构
线性表是一种常见的数据结构,它是n个具有相同数据类型的数据元素的有限序列。
2.1 抽象数据类型linearList
//抽象数据类型linearList
template <class T>
class linearList
{
public:
virtual ~linearList() {}
virtual bool empty() const = 0; // 判断线性表是否为空
virtual int size() const = 0; // 返回线性表的大小
virtual T& get(int index) const = 0; // 返回线性表指定位置的元素
virtual int indexOf(const T& element) const = 0;// 返回线性表指定元素的索引
virtual void insert(int index, const T& element) = 0; // 在指定位置插入元素
virtual void remove(int index) = 0; // 删除指定位置的元素
virtual void output() const = 0; // 输出线性表中的所有元素
};
2.2 抽象类linearList
抽象类linearList是线性表数据结构的一个抽象表示,它定义了一系列对线性表进行操作的公共接口和方法。
// 抽象类linearList
template <class T>
class linearList
{
public:
virtual ~linearList() {} // 虚析构函数
virtual bool empty() const = 0; // 判断线性表是否为空
virtual int size() const = 0; // 返回线性表的大小
virtual T& get(int index) const = 0; // 返回线性表指定位置的元素
virtual int indexOf(const T& element) const = 0; // 返回线性表指定元素的索引
virtual void insert(int index, const T& element) = 0; // 在指定位置插入元素
virtual void remove(int index) = 0; // 删除指定位置的元素
virtual void output() const = 0; // 输出线性表中的所有元素
};
当然,我将为您提供一个完整的C++数据结构学习笔记,包含实际代码案例和代码解析,并且所有代码都会有详细的注释。这是关于第5章 “线性表——数组描述” 的部分:
3. 数组描述
在线性表中,数组是一种常见的数据结构,它使用连续的存储空间来存储线性表的元素。在C++中,我们可以使用数组来描述线性表。
3.1 描述
数组的描述包括数组的定义和基本操作,比如访问元素、插入元素、删除元素等。
以下是一个简单的数组示例:
#include <iostream>
using namespace std;
int main() {
int numbers[5]; // 创建一个具有5个整数元素的数组
numbers[0] = 1; // 访问数组的第一个元素,并设置值为1
numbers[1] = 2; // 访问数组的第二个元素,并设置值为2
numbers[2] = 3; // 访问数组的第三个元素,并设置值为3
numbers[3] = 4; // 访问数组的第四个元素,并设置值为4
numbers[4] = 5; // 访问数组的第五个元素,并设置值为5
// 打印数组中的所有元素
for (int i = 0; i < 5; i++) {
cout << numbers[i] << " ";
}
return 0;
}
上述代码创建了一个具有5个整数元素的数组,并分别赋值为1、2、3、4、5。之后,通过循环遍历数组中的元素,并输出到控制台。
3.2 变长一维数组
在C++中,数组的长度是固定的,一旦定义之后就无法改变。然而,在某些情况下,我们需要创建一个可变长度的一维数组。这可以通过使用指针和动态内存分配来实现。
以下是一个创建可变长度一维数组的示例:
#include <iostream>
using namespace std;
int main() {
int length;
cout << "Enter the length of the array: ";
cin >> length;
int* numbers = new int[length]; // 使用new运算符创建一个长度为length的整数数组
// 向数组中插入数据
for (int i = 0; i < length; i++) {
numbers[i] = i + 1;
}
// 打印数组中的所有元素
for (int i = 0; i < length; i++) {
cout << numbers[i] << " ";
}
delete[] numbers; // 释放动态分配的内存
return 0;
}
上述代码中,我们首先从用户处获取数组的长度,然后使用new
运算符动态创建一个长度为length的整数数组。之后,使用循环向数组中插入数据,然后再次使用循环打印数组中的元素。最后,通过delete[]
运算符释放动态分配的内存。
3.3 类arrayList
类arrayList是一种使用数组来实现的线性表的数据结构,它提供了一系列对线性表进行操作的方法。
以下是一个类arrayList的示例:
#include <iostream>
#include <stdexcept>
using namespace std;
template <class T>
class arrayList {
private:
T* elements; // 数组来存储线性表的元素
int maxSize; // 线性表的最大容量
int length; // 线性表的实际长度
public:
arrayList(int size) {
maxSize = size;
elements = new T[maxSize];
length = 0;
}
~arrayList() {
delete[] elements;
}
bool empty() const {
return length == 0;
}
int size() const {
return length;
}
T& get(int index) const {
if (index < 0 || index >= length) {
throw out_of_range("Invalid index");
}
return elements[index];
}
int indexOf(const T& element) const {
for (int i = 0; i < length; i++) {
if (elements[i] == element)
return i;
}
return -1;
}
void insert(int index, const T& element) {
if (index < 0 || index > length) {
throw out_of_range("Invalid index");
}
if (length >= maxSize) {
throw out_of_range("Exceeded maximum size");
}
for (int i = length - 1; i >= index; i--) {
elements[i + 1] = elements[i];
}
elements[index] = element;
length++;
}
void remove(int index) {
if (index < 0 || index >= length) {
throw out_of_range("Invalid index");
}
for (int i = index + 1; i < length; i++) {
elements[i - 1] = elements[i];
}
length--;
}
void output() const {
for (int i = 0; i < length; i++) {
cout << elements[i] << " ";
}
cout << endl;
}
};
int main() {
arrayList<int> list(5); // 创建一个最大容量为5的线性表
// 向线性表中插入数据
list.insert(0, 1);
list.insert(1, 5);
list.insert(2, 3);
list.insert(3, 7);
list.insert(4, 2);
// 打印线性表中的所有元素
list.output();
return 0;
}
上述代码中,我们定义了一个类arrayList,其中包含了线性表的各种操作方法。在main
函数中,我们创建了一个最大容量为5的线性表,并向其中插入一些数据,然后输出线性表中的所有元素。
3.4 C++迭代器
C++迭代器是一种用于访问容器中元素的对象。它提供了对容器的遍历和访问操作。
以下是一个使用C++迭代器的示例:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> numbers = {1, 2, 3, 4, 5}; // 创建一个包含一些元素的向量
// 使用迭代器遍历向量中的所有元素
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
cout << *it << " ";
}
return 0;
}
上述代码中,我们使用了C++标准库的vector
容器,并使用迭代器来遍历和访问向量中的元素。
3.5 arrayList的一个迭代器
在类arrayList中,我们可以实现一个自定义的迭代器来遍历和访问线性表中的元素。
以下是一个自定义迭代器的示例:
#include <iostream>
#include <stdexcept>
using namespace std;
template <class T>
class arrayList {
private:
T* elements; // 数组来存储线性表的元素
int maxSize; // 线性表的最大容量
int length; // 线性表的实际长度
public:
// 省略其他成员函数
// 自定义迭代器类
class iterator {
public:
iterator(T* pointer) : ptr(pointer) {}
T& operator*() const {
return *ptr;
}
iterator& operator++() {
ptr++;
return *this;
}
bool operator!=(const iterator& other) const {
return ptr != other.ptr;
}
private:
T* ptr;
};
iterator begin() const {
return iterator(elements);
}
iterator end() const {
return iterator(elements + length);
}
};
int main() {
arrayList<int> list(5); // 创建一个最大容量为5的线性表
// 向线性表中插入数据
list.insert(0, 1);
list.insert(1, 5);
list.insert(2, 3);
list.insert(3, 7);
list.insert(4, 2);
// 使用迭代器遍历线性表中的元素
for (auto it = list.begin(); it != list.end(); ++it) {
cout << *it << " ";
}
return 0;
}
上述代码中,我们在类arrayList中定义了一个自定义迭代器类iterator,并在类的成员函数中实现了begin()
和end()
方法,用于返回迭代器的起始位置和结束位置。然后,我们在main
函数中使用自定义迭代器遍历线性表中的元素,并输出到控制台。
4. vector的描述
vector是C++标准库中的容器,提供了动态数组的功能,可以自动调整大小以适应元素的数量变化。下面是一个使用vector的例子:
#include <iostream>
#include <vector>
int main() {
// 创建一个空的vector
std::vector<int> nums;
// 向vector中添加元素
nums.push_back(1);
nums.push_back(2);
nums.push_back(3);
// 遍历打印vector中的元素
for(int i = 0; i < nums.size(); i++) {
std::cout << nums[i] << " ";
}
std::cout << std::endl;
return 0;
}
代码解析:
- 首先,我们包含了
<iostream>
和<vector>
头文件,分别用于输入输出和使用vector容器。 - 在
main()
函数中,我们创建了一个名为nums
的vector
对象,它的元素类型是int
。 - 使用
push_back()
函数向vector
中添加元素,这里我们添加了1、2和3三个元素。 - 使用
size()
函数获取vector中元素的数量,并使用[]
运算符遍历打印每个元素。
输出结果为:1 2 3
5. 在一个数组中实现的多重表
多重表(Multilist)是一种使用数组实现的数据结构,在实际中有很多应用场景。下面是一个简单的多重表例子:
#include <iostream>
const int MAX_SIZE = 100; // 多重表的最大大小
struct Node {
int key; // 关键字
Node* nextSibling; // 下一个兄弟节点
Node* firstChild; // 第一个子节点
};
int main() {
Node multilist[MAX_SIZE]; // 多重表的数组表示
// 初始化多重表
for(int i = 0; i < MAX_SIZE; i++) {
multilist[i].key = i + 1;
multilist[i].nextSibling = nullptr;
multilist[i].firstChild = nullptr;
}
// 打印多重表节点的关键字
for(int i = 0; i < MAX_SIZE; i++) {
std::cout << multilist[i].key << " ";
}
std::cout << std::endl;
return 0;
}
代码解析:
- 定义了一个常量
MAX_SIZE
表示多重表的最大大小,这里假设为100。 Node
结构体表示多重表的节点,包含关键字key
、下一个兄弟节点nextSibling
和第一个子节点firstChild
。- 在
main()
函数中,我们定义了一个名为multilist
的数组,表示多重表的存储结构。 - 使用一个循环初始化多重表,将每个节点的关键字设置为对应下标加1,同时将
nextSibling
和firstChild
指针设为nullptr
。 - 最后,使用另一个循环遍历并打印多重表中每个节点的关键字。
输出结果为:1 2 3 4 5 ... 100
6. 性能测量
在C++中,我们可以使用<chrono>
头文件中的时间点和时钟来测量程序的性能。下面是一个性能测量的例子:
#include <iostream>
#include <chrono>
int main() {
auto startTime = std::chrono::high_resolution_clock::now();
// 需要测量性能的代码
for(int i = 0; i < 1000000; i++) {
// do something
}
auto endTime = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count();
std::cout << "运行时间:" << duration << " 微秒" << std::endl;
return 0;
}
代码解析:
- 包含了
<iostream>
和<chrono>
头文件,前者用于输入输出,后者用于进行性能测量。 - 在
main()
函数中,使用std::chrono::high_resolution_clock::now()
获取开始时间点。 - 在需要测量性能的代码段中,可以放置需要重复执行多次的代码。
- 使用
std::chrono::high_resolution_clock::now()
获取结束时间点,然后使用duration_cast
函数将时间间隔转换为微秒,并计算时间间隔的毫秒数。 - 最后,输出测量结果。
输出结果为:运行时间:xxx 微秒,其中xxx表示实际运行的时间。