假定用一个链表保存一个班级学生清单。结点的数据有:学生姓名和考试分数。假设分数是0~100的整数。
采用箱排序可以把分数相同的结点放在同一个箱子里,然后把箱子连接起来就得到了有序的链表
#include<iostream> #include <sstream> using namespace std; class illegalParameterValue { public: illegalParameterValue() : message("Illegal parameter value") {} explicit illegalParameterValue(char *theMessage) { message = theMessage; } explicit illegalParameterValue(const string &theMessage) { message = theMessage; cout << message << endl; } void outputMessge() { cout << message << endl; } private: string message; }; // 链表结点的结构定义 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 chainList { public: // 构造函数,复制构造函数和构析函数 chainList(int initialCapacity = 10); chainList(const chainList<T> &); ~chainList(); // 抽象数据类型ADT的方法 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> void chainList<T>::checkIndex(int theIndex) const { if (theIndex < 0 || theIndex >= size()) { stringstream s; s << "theIndex " << theIndex << " is illegal"; illegalParameterValue(s.str()); } } // 构造函数和复制构造函数 template<class T> chainList<T>::chainList(int initialCapacity) { // 构造函数 if (initialCapacity < 1) { ostringstream s; s << "Initial capacity = " << initialCapacity << " Muse be > 0 "; throw illegalParameterValue(s.str()); } firstNode = nullptr; listSize = 0; } template<class T> chainList<T>::chainList(const chainList<T> &theList) { // 复制构造函数 listSize = theList.listSize; if (listSize == 0) { // 链表theList为空 firstNode = nullptr; return; } // 链表theList为非空 chainNode<T> *sourceNode = theList.firstNode; // 复制链表theList的节点 firstNode = new chainNode<T>(sourceNode->element); // 复制链表theList的首元素 sourceNode = sourceNode->next; chainNode<T> *targetNode = firstNode; // 当前链表*this的最后一个结点 while (sourceNode != nullptr) { // 复制剩余元素 targetNode->next = new chainNode<T>(sourceNode->element); targetNode = targetNode->next; sourceNode = sourceNode->next; } targetNode->next = nullptr; // 链表结束 } // 构析函数 template<class T> chainList<T>::~chainList() { // 链表构析函数,删除链表的所有节点 while (firstNode != nullptr) { // 删除首结点 chainNode<T> *nextNode = firstNode->next; delete firstNode; firstNode = nextNode; } } // get方法 template<class T> T &chainList<T>::get(int theIndex) const { // 返回索引为theIndex的㢝 // 若该元素不存在,则抛出异常 checkIndex(theIndex); // 移向所需要的结点 chainNode<T> *currentNode = firstNode; for (int i = 0; i < theIndex; ++i) currentNode = currentNode->next; return currentNode->element; } // 返回元素theElement首次出现时的索引 template<class T> int chainList<T>::indexOf(const T &theElement) const { // 返回元素theElement首次出现时的索引 // 若该元素不存在,则返回-1 // 搜寻链表寻找元素theElement chainNode<T> *currentNode = firstNode; int index = 0; while (currentNode != nullptr && currentNode->element != theElement) { // 移向下一个结点 currentNode = currentNode->next; ++index; } // 确定是否找到所需的元素 if (currentNode == nullptr) return -1; else return index; } // 删除索引为theIndex的元素 template<class T> void chainList<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; delete deleteNode; } // 插入theElement并使得其索引为theIndex template<class T> void chainList<T>::insert(int theIndex, const T &theElement) { // 在索引为theIndex的位置上 // 若该位置非法,则抛出异常 if (theIndex < 0 || theIndex > listSize) { // 无效索引 ostringstream s; s << "index = " << theIndex << " size = " << listSize; throw illegalParameterValue(s.str()); } 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; // 在p之后插入 p->next = new chainNode<T>(theElement, p->next); } ++listSize; } template<class T> void chainList<T>::output(ostream &out) const { // 把链表放入输出流 for (auto *currentNode = firstNode; currentNode != nullptr; currentNode = currentNode->next) out << currentNode->element; } // 重载 template<class T> ostream &operator<<(ostream &out, const chainList<T> &x) { x.output(out); return out; }
struct studentRecord { string name; int score; // 重载类型转换操作符int(),这样可以使用+、/、<=和!=这些算数和关系操作符 explicit operator int() const { return score; } // 重载类型转换操作符int()转换为int类型 // 重载操作符int()只有在操作符号!=和<<以外操作中被调用 int operator!=(const studentRecord &x) const { return score != x.score; } // 重载运算符 }; // 重载<< ostream &operator<<(ostream &out, const studentRecord &x) { out << x.name << ": " << x.score << endl; return out; }
// 使用链表的多个方法进行箱排序 void binSort(chainList<studentRecord> &theChain, int range) { // 按分数排序 chainList<studentRecord> *bin; // 声明箱子 bin = new chainList<studentRecord>[range + 1]; // 总共有range+1个箱子 // 把学生记录从链表中取出,然后分配到箱子中 int numberOfElements = theChain.size(); // 记录链表中元素数量 for (int i = 0; i < numberOfElements; ++i) { studentRecord x = theChain.get(0); // 得到链表中第一个结点 theChain.erase(0); // 将该节点从链表中删除 bin[x.score].insert(0, x); // 将该节点数据连接到对应分数的箱子里 } // 从箱子中收集元素 for (int j = range; j >= 0; --j) { while (!bin[j].empty()) { // 如果第j个箱子中的元素不为0 studentRecord x = bin[j].get(0); // 拿出第j个箱子中的第一个元素 bin[j].erase(0); // 然后从箱子中删除该元素 theChain.insert(0, x); // 将该元素通过头插法加入到链表中 } } delete[] bin; // 最后删除箱子 }
#include<iostream> #include <sstream> using namespace std; class illegalParameterValue { public: illegalParameterValue() : message("Illegal parameter value") {} explicit illegalParameterValue(char *theMessage) { message = theMessage; } explicit illegalParameterValue(const string &theMessage) { message = theMessage; cout << message << endl; } void outputMessge() { cout << message << endl; } private: string message; }; // 链表结点的结构定义 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 chainList { public: // 构造函数,复制构造函数和构析函数 chainList(int initialCapacity = 10); chainList(const chainList<T> &); ~chainList(); // 抽象数据类型ADT的方法 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> void chainList<T>::checkIndex(int theIndex) const { if (theIndex < 0 || theIndex >= size()) { stringstream s; s << "theIndex " << theIndex << " is illegal"; illegalParameterValue(s.str()); } } // 构造函数和复制构造函数 template<class T> chainList<T>::chainList(int initialCapacity) { // 构造函数 if (initialCapacity < 1) { ostringstream s; s << "Initial capacity = " << initialCapacity << " Muse be > 0 "; throw illegalParameterValue(s.str()); } firstNode = nullptr; listSize = 0; } template<class T> chainList<T>::chainList(const chainList<T> &theList) { // 复制构造函数 listSize = theList.listSize; if (listSize == 0) { // 链表theList为空 firstNode = nullptr; return; } // 链表theList为非空 chainNode<T> *sourceNode = theList.firstNode; // 复制链表theList的节点 firstNode = new chainNode<T>(sourceNode->element); // 复制链表theList的首元素 sourceNode = sourceNode->next; chainNode<T> *targetNode = firstNode; // 当前链表*this的最后一个结点 while (sourceNode != nullptr) { // 复制剩余元素 targetNode->next = new chainNode<T>(sourceNode->element); targetNode = targetNode->next; sourceNode = sourceNode->next; } targetNode->next = nullptr; // 链表结束 } // 构析函数 template<class T> chainList<T>::~chainList() { // 链表构析函数,删除链表的所有节点 while (firstNode != nullptr) { // 删除首结点 chainNode<T> *nextNode = firstNode->next; delete firstNode; firstNode = nextNode; } } // get方法 template<class T> T &chainList<T>::get(int theIndex) const { // 返回索引为theIndex的㢝 // 若该元素不存在,则抛出异常 checkIndex(theIndex); // 移向所需要的结点 chainNode<T> *currentNode = firstNode; for (int i = 0; i < theIndex; ++i) currentNode = currentNode->next; return currentNode->element; } // 返回元素theElement首次出现时的索引 template<class T> int chainList<T>::indexOf(const T &theElement) const { // 返回元素theElement首次出现时的索引 // 若该元素不存在,则返回-1 // 搜寻链表寻找元素theElement chainNode<T> *currentNode = firstNode; int index = 0; while (currentNode != nullptr && currentNode->element != theElement) { // 移向下一个结点 currentNode = currentNode->next; ++index; } // 确定是否找到所需的元素 if (currentNode == nullptr) return -1; else return index; } // 删除索引为theIndex的元素 template<class T> void chainList<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; delete deleteNode; } // 插入theElement并使得其索引为theIndex template<class T> void chainList<T>::insert(int theIndex, const T &theElement) { // 在索引为theIndex的位置上 // 若该位置非法,则抛出异常 if (theIndex < 0 || theIndex > listSize) { // 无效索引 ostringstream s; s << "index = " << theIndex << " size = " << listSize; throw illegalParameterValue(s.str()); } 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; // 在p之后插入 p->next = new chainNode<T>(theElement, p->next); } ++listSize; } template<class T> void chainList<T>::output(ostream &out) const { // 把链表放入输出流 for (auto *currentNode = firstNode; currentNode != nullptr; currentNode = currentNode->next) out << currentNode->element; } // 重载 template<class T> ostream &operator<<(ostream &out, const chainList<T> &x) { x.output(out); return out; } #include"chainList.cpp" // 用链表保存一个班级学生的清单 // 节点的数据域有:学生姓名,分数 // 假设分数是0~100的整数 struct studentRecord { string name; int score; explicit operator int() const { return score; } int operator!=(const studentRecord &x) const { return score != x.score; } }; ostream &operator<<(ostream &out, const studentRecord &x) { out << x.name << ": " << x.score << endl; return out; } // 使用链表的多个方法进行箱排序 void binSort(chainList<studentRecord> &theChain, int range) { // 按分数排序 chainList<studentRecord> *bin; // 声明箱子 bin = new chainList<studentRecord>[range + 1]; // 总共有range+1个箱子 // 把学生记录从链表中取出,然后分配到箱子中 int numberOfElements = theChain.size(); // 记录链表中元素数量 for (int i = 0; i < numberOfElements; ++i) { studentRecord x = theChain.get(0); // 得到链表中第一个结点 theChain.erase(0); // 将该节点从链表中删除 bin[x.score].insert(0, x); // 将该节点数据连接到对应分数的箱子里 } // 从箱子中收集元素 for (int j = range; j >= 0; --j) { while (!bin[j].empty()) { // 如果第j个箱子中的元素不为0 studentRecord x = bin[j].get(0); // 拿出第j个箱子中的第一个元素 bin[j].erase(0); // 然后从箱子中删除该元素 theChain.insert(0, x); // 将该元素通过头插法加入到链表中 } } delete[] bin; // 最后删除箱子 } int main() { auto *studentRecords = new chainList<studentRecord>(10); int score; string name; for (int i = 0; i < 10; ++i) { auto *sr = new studentRecord; // 为结点申请空间 cin >> name >> score; sr->score = score; // 为结点赋值 sr->name = name; studentRecords->insert(i, *sr); // 将结点插入链表中 } // 查看输入结果 cout << *studentRecords << endl; // 对链表进行箱排序 binSort(*studentRecords, 5); cout << "排序后结果" << endl; cout << *studentRecords << endl; }
A 2 B 4 C 5 D 4 E 3 F 0 G 4 H 3 I 4 J 4
A: 2 B: 4 C: 5 D: 4 E: 3 F: 0 G: 4 H: 3 I: 4 J: 4 排序后结果 F: 0 A: 2 E: 3 H: 3 B: 4 D: 4 G: 4 I: 4 J: 4 C: 5