顺序表
使用数组实现
构造函数
template<class T>
arrayList<T>::arrayList(int initialcapacity) {
if (initialcapacity < 1) {
throw "初始数组容量必须大于 0";
}
arrayLength = initialcapacity;
element = new T[arrayLength];
listSize = 0;
}
时间复杂度:
复制构造函数
template<class T>
arrayList<T>::arrayList(const arrayList<T>& theList) {
arrayLength = theList.arrayLength; // 数组容量
listSize = theList.listSize; // 元素个数
element = new T[arrayLength];
copy(theList.element, theList.element + listSize, element);
}
时间复杂度:
改变数组长度
template<class T>
void changeLength(T*& a, int oldLength, int newLength) {
if (newLength < 0) {
throw "新长度必须大于 0";
}
T* temp = new T[newLength]; // 新数组
// 需要复制的元素个数
int number = min(oldLength, newLength);
// 拷贝元素到新数组(temp)
copy(a, a + number, temp);
delete[] a; // 释放老数组的内存空间
a = temp; // 重新指向新数组
};
创建新数组:
复制到新数组:
插入元素
template<class T>
void arrayList<T>::insert(int theIndex, const T& theElement) {
// 在索引 theIndex 处插入元素 theElement
if (theIndex < 0 || theIndex > listSize) {
// 无效索引
ostringstream s;
s << "index = " << theIndex << " size = " << listSize;
throw s.str();
}
// 有效索引, 确定数组是否已满
if (listSize == arrayLength) {
// 数组空间已满, 数组长度倍增
changeLength(element, arrayLength, 2 * arrayLength);
arrayLength *= 2;
}
// 把元素向右移动一个位置
copy_backward(element + theIndex, element + listSize, element + listSize + 1);
element[theIndex] = theElement;
listSize++; // 元素个数加 1
}
如果是无效索引, 时间复杂度:
如果数组要加倍, 时间复杂度:
移动元素, 时间复杂度:
为什么需要以倍数的方式增加?
长度为 1 的空表, 如果连续执行 次插入, 每次扩容 1 位, 假设均插入尾部, 则插入的时间复杂度为 , 扩容(实际上为创建新数组, 包括初始长度为 1 的空表)的时间复杂度为 , 这里每次扩容 2 位也一样
如果 2 倍增加, 则插入时间复杂度依旧是, 但是扩容的时间复杂度为
如果成 i 倍增长(如果 i 不是整数, 则每次扩容要取整, 比如 i=1.5, 第一次扩容为 , 第二次扩容为 3, 第三次为 ), 令 , 则其时间复杂度为
顺序存储的线性表, 扩容系数为 1.5 倍时, 尾部插入一个元素的平均时间复杂度为?
前面已知扩容的时间复杂度为 , 平均到 n 个元素上, 就是 , 尾部插入的时间复杂度为 , 整体时间复杂度就是
顺序存储的线性表, 扩容系数为常数 2 时, 尾部插入一个元素的平均时间复杂度为?
注意这里不是扩容 2 倍, 而是扩容系数, 也就是容量 +2, 那么扩容时间复杂度为 , 平均一下就是 , 尾部插入是 , 整体就是
判断索引有效性
template<class T>
void arrayList<T>::checkIndex(int theIndex) const {
// 确定索引 theIndex 在 0 和 listSize - 1 之间
if (theIndex < 0 || theIndex >= listSize) {
ostringstream s;
s << "index = " << theIndex << " size = " << listSize;
throw s.str();
}
}
时间复杂度:
返回索引对应的数据
template<class T>
T& arrayList<T>::get(int theIndex) const {
checkIndex(theIndex); // 若此元素不存在, 则抛出异常
return element[theIndex];
}
时间复杂度:
删除元素
template<class T>
void arrayList<T>::erase(int theIndex) {
// 删除其索引为 theIndex 的元素
// 如果该元素不存在, 则抛出异常 illegalIndex
checkIndex(theIndex);
// 把 theIndex 后面的往前移一位
// 即把 theIndex 后面的数据复制到 theIndex 的位置
copy(element + theIndex + 1, element + listSize, element + theIndex);
element[--listSize].~T(); // 调用数组的析构函数, 删掉最后一个元素
}
如果没有要删除的元素, 时间复杂度:
如果存在要删除的元素, 时间复杂度:
第一次出现的下标
template<class T>
int arrayList<T>::indexOf(const T& theElement) const {
int theIndex = (int)(find(element, element + listSize, theElement) - element);
// 确定元素 theElement 是否找到
if (theIndex == listSize) // 没有找到
return -1;
else return theIndex;
return 0;
}
时间复杂度:
完整代码
#include<iostream>
#include<sstream>
using namespace std;
// 抽象类
template<class T> class linearList {
public:
virtual ~linearList() {};
// 判断线性表是否为空
virtual bool empty() const = 0;
// 返回线性表的元素个数
virtual int size() const = 0;
// 返回索引为 theIndex 的元素
virtual T& get(int theIndex) const = 0;
// 返回元素theElement第一次出现时的索引
virtual int indexOf(const T& theElement) const = 0;
// 删除索引为 theIndex 的元素
virtual void erase(int theIndex) = 0;
// 把 theElement 插入线性表中索引为 theIndex 的位置上
virtual void insert(int theIndex, const T& theElement) = 0;
// 把线性表插入输出流 out
virtual void output(ostream& out) const = 0;
};
// 改变数组长度
template<class T>
void changeLength(T*& a, int oldLength, int newLength) {
if (newLength < 0) {
throw "新长度必须大于 0";
}
T* temp = new T[newLength]; // 新数组
int number = min(oldLength, newLength); // 需要复制的元素个数
copy(a, a + number, temp); // 拷贝元素到新数组(temp)
delete[] a; // 释放老数组的内存空间
a = temp; // 重新指向新数组
};
template<class T>
class arrayList:public linearList<T> {
public:
// 构造函数
arrayList(int initialcapacity = 10);
// 复制构造函数
arrayList(const arrayList<T>&);
// 析构函数
~arrayList() {
delete[] element;
}
// 类方法
bool empty() const {
return listSize == 0;
}
int size() const {
return listSize;
}
T& get(int theIndex) const;
int indexOf(const T& theElement) const;
void erase(int theIndex);
void insert(int theIndex, const T& theElement);
void output(ostream& out) const;
int capacity() const {
return arrayLength;
}
protected:
// 若索引 theIndex 无效, 则抛出异常
void checkIndex(int theIndex) const;
T* element; // 一维数组
int arrayLength; // 数组容量
int listSize; // 元素个数
};
// 构造函数
template<class T>
arrayList<T>::arrayList(int initialcapacity) {
if (initialcapacity < 1) {
throw "初始数组容量必须大于 0";
}
arrayLength = initialcapacity;
element = new T[arrayLength];
listSize = 0;
}
// 复制构造函数
template<class T>
arrayList<T>::arrayList(const arrayList<T>& theList) {
arrayLength = theList.arrayLength; // 数组容量
listSize = theList.listSize; // 元素个数
element = new T[arrayLength];
copy(theList.element, theList.element + listSize, element);
}
// 判断索引有效性
template<class T>
void arrayList<T>::checkIndex(int theIndex) const {
// 确定索引 theIndex 在 0 和 listSize - 1 之间
if (theIndex < 0 || theIndex >= listSize) {
throw "索引非法";
}
}
// 返回索引为 theIndex 的元素
template<class T>
T& arrayList<T>::get(int theIndex) const {
checkIndex(theIndex); // 若此元素不存在, 则抛出异常
return element[theIndex];
}
// 返回元素 theElement 第一次出现时的索引
// 若该元素不存在, 则返回 - 1
template<class T>
int arrayList<T>::indexOf(const T& theElement) const {
int theIndex = (int)(find(element, element + listSize, theElement) - element);
// 确定元素 theElement 是否找到
if (theIndex == listSize) // 没有找到
return -1;
else return theIndex;
return 0;
}
template<class T>
void arrayList<T>::erase(int theIndex) {
// 删除其索引为 theIndex 的元素
// 如果该元素不存在, 则抛出异常 illegalIndex
checkIndex(theIndex);
// 把 theIndex 后面的往前移一位
// 即把 theIndex 后面的数据复制到 theIndex 的位置
copy(element + theIndex + 1, element + listSize, element + theIndex);
element[--listSize].~T(); // 调用数组的析构函数, 删掉最后一个元素
}
template<class T>
void arrayList<T>::insert(int theIndex, const T& theElement) {
// 在索引 theIndex 处插入元素 theElement
if (theIndex < 0 || theIndex > listSize) {
// 无效索引
throw "索引非法";
}
// 有效索引, 确定数组是否已满
if (listSize == arrayLength) {
// 数组空间已满, 数组长度倍增
changeLength(element, arrayLength, 2 * arrayLength);
arrayLength *= 2;
}
// 把元素向右移动一个位置
copy_backward(element + theIndex, element + listSize, element + listSize + 1);
element[theIndex] = theElement;
listSize++; // 元素个数加 1
}
template<class T>
void arrayList<T>::output(ostream& out) const {
// 把线性表插入输出流
copy(element, element + listSize, ostream_iterator<T>(cout, " "));
}
// 重载 <<
template <class T>
ostream& operator<<(ostream& out, const arrayList<T>& x) {
x.output(out);
return out;
}
int main() {
arrayList<int> list(10);
list.insert(0, 10);
list.insert(1, 18);
cout << "当前栈: " << list << endl;
list.erase(1);
cout << "删除索引 1 的元素后: " << list << endl;
return 0;
}
单向链表
构造函数
template<class T>
chain<T>::chain(int initialcapacity) {
if (initialcapacity < 1) {
throw "初始容量必须大于 0";
}
firstNode = NULL;
listSize = 0;
}
时间复杂度:
复制构造函数
// 复制构造函数
template<class T>
chain<T>::chain(const chain<T>& theList) {
listSize = theList.listSize;
// 如果链表 theList 为空
if (listSize == 0) {
firstNode = NULL;
return;
}
// 如果链表 theList 非空
// 要复制链表 theList 的节点
chainNode<T>* sourceNode = theList.firstNode;
// 复制链表 theList 的首元素
firstNode = new chainNode<T>(sourceNode->element);
// sourceNode 指向下一个节点
sourceNode = sourceNode->next;
// targetNode 指向当前节点
chainNode<T>* targetNode = firstNode;
// 遍历节点, 直到最后指向 NULL
while (sourceNode != NULL) {
// 复制剩余元素
targetNode->next = new chainNode<T>(sourceNode->element);
targetNode = targetNode->next;
sourceNode = sourceNode->next;
}
targetNode->next = NULL; // 链表结束
}
时间复杂度:
析构函数
template<class T>
chain<T>::~chain() {
while (firstNode != NULL) {
// 不断删除首节点, 则下一个节点就成为首节点
chainNode<T>* nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;
}
}
时间复杂度:
插入元素
template<class T>
void chain<T>::insert(int theIndex, const T& theElement) {
// 在索引为 theIndex 的位置上插入元素 theElement
if (theIndex < 0 || theIndex > listSize) {
// 无效索引, 即小于 0 和多于当前元素个数
throw "无效索引";
}
else if (theIndex == 0) {
// 在链表头插入
firstNode = new chainNode<T>(theElement, firstNode);
}
else {
// 寻找新元素的前驱
chainNode<T>* p = firstNode;
for (int i = 0; i < theIndex - 1; i++) {
p = p->next;
}
// 前驱节点的下一个节点是 theElement
// theElement 的下一个节点是前驱结点的下一个节点
p->next = new chainNode<T>(theElement, p->next);
}
listSize++;
}
时间复杂度:
删除元素
template<class T>
void chain<T>::erase(int theIndex) {
// 删除索引为 theIndex 的元素
// 若该元素不存在, 则抛出异常
checkIndex(theIndex);
// 索引有效, 需找要删除的元素节点
chainNode<T>* deleteNode;
if (theIndex == 0) {
// 删除链表的首节点
deleteNode = firstNode;
firstNode = firstNode->next;
}
else {
// 用指针 p 指向要删除节点的前驱节点
chainNode<T>* p = firstNode;
// 一直循环, 直到指向前驱节点
for (int i = 0; i < theIndex - 1; i++) {
p = p->next;
}
// 要删除的节点就是前驱节点的下一个节点
deleteNode = p->next;
p->next = p->next->next;
// 元素个数减一
listSize--;
// 删除 deleteNode 指向的节点
delete deleteNode;
}
}
有效索引时, 时间复杂度:
第一次出现索引
template<class T>
int chain<T>::indexOf(const T& theElement) const {
// 返回元素 theElement 首次出现时的索引
// 若该元素不存在, 则返回 - 1
// 搜索链表寻找元素 theElement
chainNode<T>* currentNode = firstNode;
int index = 0;
// 直到当前节点等于 theElement 或者 NULL 时退出
while (currentNode != NULL && currentNode->element != theElement) {
// 移向下一个节点
currentNode = currentNode->next;
index++;
}
// 确定是否找到所需的元素
if (currentNode == NULL)
return -1;
else
return index;
}
平均时间复杂度:
获取索引对应的值
template<class T>
T& chain<T>::get(int theIndex) const {
// 判断索引有效性
checkIndex(theIndex);
// 移向所需要的节点
chainNode<T>* currentNode = firstNode;
for (int i = 0; i < theIndex; i++) {
currentNode = currentNode->next;
}
return currentNode->element;
}
时间复杂度:
完整代码
#include<iostream>
using namespace std;
// 抽象类
template<class T> class linearList {
public:
virtual ~linearList() {};
// 判断线性表是否为空
virtual bool empty() const = 0;
// 返回线性表的元素个数
virtual int size() const = 0;
// 返回索引为 theIndex 的元素
virtual T& get(int theIndex) const = 0;
// 返回元素theElement第一次出现时的索引
virtual int indexOf(const T& theElement) const = 0;
// 删除索引为 theIndex 的元素
virtual void erase(int theIndex) = 0;
// 把 theElement 插入线性表中索引为 theIndex 的位置上
virtual void insert(int theIndex, const T& theElement) = 0;
// 把线性表插入输出流 out
virtual void output(ostream& out) const = 0;
};
// 节点元素类, 具有 next 指针和 element 数据
template <class T>
struct chainNode {
// 数据成员
T element;
chainNode<T>* next;
// 方法
chainNode() { }
chainNode(const T& element) {
this->element = element;
}
chainNode(const T& element, chainNode<T>* next) {
this->element = element;
this->next = next;
}
};
template<class T>
class chain:public linearList<T> {
public:
// 构造函数
chain(int initialcapacity = 10);
// 复制构造函数
chain(const chain<T>&);
// 析构函数
~chain();
// 方法
bool empty() const {
return listSize == 0;
}
int size() const {
return listSize;
}
T& get(int theIndex) const;
int indexOf(const T& theElement) const;
void erase(int theIndex);
void insert(int theIndex, const T& theElement);
void output(ostream& out)const;
protected:
void checkIndex(int theIndex)const;
chainNode<T>* firstNode; // 指向链表第一个节点的指针
int listSize; // 元素个数
};
// 构造函数
template<class T>
chain<T>::chain(int initialcapacity) {
if (initialcapacity < 1) {
throw "初始容量必须大于 0";
}
firstNode = NULL;
listSize = 0;
}
// 复制构造函数
template<class T>
chain<T>::chain(const chain<T>& theList) {
listSize = theList.listSize;
// 如果链表 theList 为空
if (listSize == 0) {
firstNode = NULL;
return;
}
// 如果链表 theList 非空
// 要复制链表 theList 的节点
chainNode<T>* sourceNode = theList.firstNode;
// 复制链表 theList 的首元素
firstNode = new chainNode<T>(sourceNode->element);
// sourceNode 指向下一个节点
sourceNode = sourceNode->next;
// targetNode 指向当前节点
chainNode<T>* targetNode = firstNode;
// 遍历节点, 直到最后指向 NULL
while (sourceNode != NULL) {
// 复制剩余元素
targetNode->next = new chainNode<T>(sourceNode->element);
targetNode = targetNode->next;
sourceNode = sourceNode->next;
}
targetNode->next = NULL; // 链表结束
}
// 析构函数
template<class T>
chain<T>::~chain() {
while (firstNode != NULL) {
// 不断删除首节点, 则下一个节点就成为首节点
chainNode<T>* nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;
}
}
// 获取索引对应的元素
template<class T>
T& chain<T>::get(int theIndex) const {
// 判断索引有效性
checkIndex(theIndex);
// 移向所需要的节点
chainNode<T>* currentNode = firstNode;
for (int i = 0; i < theIndex; i++) {
currentNode = currentNode->next;
}
return currentNode->element;
}
// 元素第一次出现的下标
template<class T>
int chain<T>::indexOf(const T& theElement) const {
// 返回元素 theElement 首次出现时的索引
// 若该元素不存在, 则返回 - 1
// 搜索链表寻找元素 theElement
chainNode<T>* currentNode = firstNode;
int index = 0;
// 直到当前节点等于 theElement 或者 NULL 时退出
while (currentNode != NULL && currentNode->element != theElement) {
// 移向下一个节点
currentNode = currentNode->next;
index++;
}
// 确定是否找到所需的元素
if (currentNode == NULL)
return -1;
else
return index;
}
template<class T>
void chain<T>::erase(int theIndex) {
// 删除索引为 theIndex 的元素
// 若该元素不存在, 则抛出异常
checkIndex(theIndex);
// 索引有效, 需找要删除的元素节点
chainNode<T>* deleteNode;
if (theIndex == 0) {
// 删除链表的首节点
deleteNode = firstNode;
firstNode = firstNode->next;
}
else {
// 用指针 p 指向要删除节点的前驱节点
chainNode<T>* p = firstNode;
// 一直循环, 直到指向前驱节点
for (int i = 0; i < theIndex - 1; i++) {
p = p->next;
}
// 要删除的节点就是前驱节点的下一个节点
deleteNode = p->next;
p->next = p->next->next;
// 元素个数减一
listSize--;
// 删除 deleteNode 指向的节点
delete deleteNode;
}
}
template<class T>
void chain<T>::insert(int theIndex, const T& theElement) {
// 在索引为 theIndex 的位置上插入元素 theElement
if (theIndex < 0 || theIndex > listSize) {
// 无效索引, 即小于 0 和多于当前元素个数
throw "无效索引";
}
else if (theIndex == 0) {
// 在链表头插入
firstNode = new chainNode<T>(theElement, firstNode);
}
else {
// 寻找新元素的前驱
chainNode<T>* p = firstNode;
for (int i = 0; i < theIndex - 1; i++) {
p = p->next;
}
// 前驱节点的下一个节点是 theElement
// theElement 的下一个节点是前驱结点的下一个节点
p->next = new chainNode<T>(theElement, p->next);
}
listSize++;
}
template<class T>
void chain<T>::output(ostream& out) const {
// 把链表放入输出流
for (chainNode<T>* currentNode = firstNode; currentNode != NULL; currentNode = currentNode->next) {
out << currentNode->element << " ";
}
}
// 重载 <<
template<class T>
ostream& operator << (ostream & out, const chain<T>&x) {
x.output(out);
return out;
}
template<class T>
void chain<T>::checkIndex(int theIndex) const {
// 确定索引 theIndex 在 0 和 listSize - 1 之间
if (theIndex < 0 || theIndex >= listSize) {
throw "无效索引";
}
}
int main() {
try {
chain<int> list(10);
list.insert(0, 10);
list.insert(1, 10);
list.insert(3, 10);
cout << "原链表: " << list << endl;
list.erase(1);
cout << "删除索引为 1 的元素后: " << list << endl;
}
catch (const char* c) {
cout << "捕获异常: " << c << endl;
}
return 0;
}
箱子排序
普通排序, 时间复杂度 分数相同的放在同一个箱子里, 再把箱子按顺序连接
箱子排序不会改变分数相同的节点的相对次序, 因此成为“稳定排序”
步骤
- 连续地删除链表首元素并将其插入到相应箱子链表的首部
- 逐个删除每个箱子中的元素(从最后一个箱子开始)并将其插入到一个初始为空的链表的首部
代码实现
#include<iostream>
#include<string>
#include<list>
using namespace std;
struct studentRecord {
int score;
string name;
int operator !=(const studentRecord& x) const {
return score != x.score;
}
operator int() const { return score; }
};
ostream& operator << (ostream& out, const studentRecord& x) {
out << x.score << ' ' << x.name << endl;
return out;
};
void binSort(list<studentRecord>& theChain, int range) {
// 按分数排序, 对箱子初始化
list<studentRecord> *bin;
bin = new list<studentRecord>[range + 1];
// 把学生记录从链表取出, 然后分配到箱子里
size_t numberOfElements = theChain.size();
for (int i = 1; i <= numberOfElements; i++) {
studentRecord x = theChain.front(); // 取出头节点
theChain.pop_front(); // 删除头节点
bin[x.score].emplace_front(x); // 插入箱子头部
}
// 从箱子中收集元素
for (int j = range; j >= 0; j--) {
// 遍历箱子中的元素
while (!bin[j].empty()) {
studentRecord x = bin[j].front(); // 取出箱子头节点
bin[j].pop_front();
theChain.emplace_front(x); // 插入链表头部
}
}
delete[] bin;
}
int main() {
list<studentRecord> theChain;
studentRecord x = { 5, "Jane" };
studentRecord y = { 3, "Ming" };
studentRecord z = { 2, "May" };
studentRecord n = { 4, "Quene" };
theChain.emplace_back(x);
theChain.emplace_back(y);
theChain.emplace_back(z);
theChain.emplace_back(n);
list<studentRecord>::iterator it = theChain.begin();
while (it != theChain.end()) {
cout << *it;
it++;
} // 5 3 2 4
cout << endl;
// 5 个桶, 代表分数取值 1~5
binSort(theChain, 5);
it = theChain.begin();
while (it != theChain.end()) {
cout << *it;
it++;
} // 2 3 4 5
cout << endl;
return 0;
}
- 第一个 for 循环, 时间复杂度
- 第二个 for 循环, 时间复杂度 (这里的 n 对应 while 循环)
n: 元素个数
range: 箱子个数
基数排序
把数分解成基数, 如用基数 10 将 213 分解成
再对基数 2, 1, 3 进行排序
箱子排序的问题
如果有 1000 个箱子, 但只有 10 个节点需要排序, 那么箱子的初始化需要 1000 步, 节点的分配需要 10 步, 收集节点需要 1000 步, 共 2010 步, 性能差
时间复杂度:
基数排序(多阶段箱子排序)
步骤
- 将数据切成 c 段(由基数 r 决定)
- 对每一段进行箱子排序, 每次排序只需要 r 个箱子
箱子初始化 r 步, 节点初始化 n 步, 收集节点 r 步, 共执行 c 次
时间复杂度:
代码实现
#include<iostream>
#include<string>
#include<list>
#include <math.h>
using namespace std;
struct studentRecord {
int score;
string name;
int operator !=(const studentRecord& x) const {
return score != x.score;
}
operator int() const { return score; }
};
ostream& operator << (ostream& out, const studentRecord& x) {
out << x.score << ' ' << x.name << endl;
return out;
};
void radixSort(list<studentRecord>& theChain, int radix, int c) {
// 循环 c 次
for (int i = 1; i <= c; i++) {
// 箱子初始化
list<studentRecord>* bin;
bin = new list<studentRecord>[radix + 1];
// 把学生记录从链表取出, 然后分配到箱子里
size_t numberOfElements = theChain.size();
for (int j = 1; j <= numberOfElements; j++) {
studentRecord x = theChain.front(); // 取出头节点
theChain.pop_front(); // 删除头节点
bin[x.score % (int)pow(radix, i) / (int)pow(radix, i - 1)].emplace_front(x);
}
// 从箱子中收集元素
for (int j = radix; j >= 0; j--) {
// 遍历箱子中的元素
while (!bin[j].empty()) {
studentRecord x = bin[j].front(); // 取出箱子头节点
bin[j].pop_front();
theChain.emplace_front(x); // 插入链表头部
}
}
delete[] bin;
}
}
int main() {
list<studentRecord> theChain;
int score[10] = { 5, 109, 123, 340, 20, 890, 560, 198, 87, 100 };
string name[10] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };
int len = sizeof(score) / sizeof(score[0]);
for (int i = 0; i < len; i++) {
studentRecord x = { score[i], name[i] };
theChain.emplace_back(x);
}
list<studentRecord>::iterator it = theChain.begin();
while (it != theChain.end()) {
cout << *it;
it++;
}
cout << endl;
radixSort(theChain, 10, 3);
it = theChain.begin();
while (it != theChain.end()) {
cout << *it;
it++;
}
cout << endl;
return 0;
}
其中, 需要注意的是每一次循环, 其箱子的索引为
顺序表逆序(转置)
要求空间复杂度为
这里直接使用数组代替顺序表
#include<iostream>
using namespace std;
int main() {
int score[10] = { 5, 109, 123, 340, 20, 890, 560, 198, 87, 100 };
int len = sizeof(score) / sizeof(score[0]);
int temp;
// 从一半处开始前后交换
for (int i = 0; i < len / 2; i++) {
temp = score[i];
score[i] = score[len - i - 1];
score[len - i - 1] = temp;
}
// 100 87 198 560 890 20 340 123 109 5
for (int i = 0; i < len; i++) {
cout << score[i] << " ";
}
return 0;
}
时间复杂度:
分段逆序
要求空间复杂度 即将一个顺序表 变成
步骤
- 将 变成
- 将 变成
- 整体变成
- 将整体逆序, 变成
代码
#include<iostream>
using namespace std;
int main() {
int score[10] = { 5, 109, 123, 340, 20, 890, 560, 198, 87, 100 };
int n = 4;
int m = 6;
int len = sizeof(score) / sizeof(score[0]); // 数组长度
int temp;
// 前半段逆序
for (int i = 0; i < n / 2; i++) {
temp = score[i];
score[i] = score[n - i - 1];
score[n - i - 1] = temp;
}
// 后半段逆序
int* s = score + n;
for (int i = 0; i < m / 2; i++) {
temp = s[i];
s[i] = s[m - i - 1];
s[m - i - 1] = temp;
}
// 整体逆序
for (int i = 0; i < len / 2; i++) {
temp = score[i];
score[i] = score[len - i - 1];
score[len - i - 1] = temp;
}
for (int i = 0; i < len; i++) {
cout << score[i] << " ";
}
return 0;
}
时间复杂度:
有序顺序表合并
要求空间复杂度 即一个顺序表 , 其中 是升序的, 也是升序的, 需要将整个列表变成升序的
步骤
- 判断 a[i] 是否比 b[j] 大, 如果 a[i] > b[j], 两者交换
- 由于 a[i+1]~a[n] 都是比 a[i] 大的, 所以肯定不能仅仅把 a[i] 换到 b[j] 的位置, 还要将 a[i] 重新移回 a[i+1] 的前面, 也就是 b[j] 的后一位
代码
#include<iostream>
using namespace std;
void swap(int* a, int* b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int main() {
int score[10] = { 5, 109, 123, 340, 20, 110, 260, 698, 787, 800 };
int len = sizeof(score) / sizeof(score[0]);
int i = 0, j = 4; // 两个子序列的起始位置
while (j < len && i < j) {
if (score[i] <= score[j]) {
// 如果 a[i] <= b[j], 则下一步 a[i+1] 和 b[j] 的对比, 以此类推
i++;
}
else {
// 如果 a[i] > b[j], 交换 a[i] 和 b[i]
// ... a[i] a[i+1].... b[j] ... => ... b[j] a[i+1] .... a[i] ...
swap(score[i], score[j]);
// 将 a[i] 移动到 a[i+1] ~ a[n] 之前
// 即 ... b[j] a[i] a[i+1] .......
for (int k = j - 1; k > i; k--) {
swap(score[k], score[k + 1]);
}
i++;
j++;
}
}
for (int i = 0; i < len; i++) {
cout << score[i] << " ";
}
return 0;
}