线性表—链式描述
一、单向链表代码
chainNode.h(链表节点的结构定义)
// chain node#ifndef chainNode_
#define chainNode_template <class T>
struct chainNode
{// data membersT element;chainNode<T> *next;// methodschainNode() {}chainNode(const T& element){this->element = element;}chainNode(const T& element, chainNode<T>* next){this->element = element;this->next = next;}
};#endif
节点chainNode数据成员:element为元素
*next指向下一节点的指针
chain.h
// linked implementation of a linear list
// derives from abstract class linearList just to make sure
// all methods of the ADT are implemented#ifndef chain_
#define chain_#include<iostream>
#include<sstream>
#include<string>
#include "linearList.h"
#include "chainNode.h"
#include "myExceptions.h"using namespace std;class linkedDigraph;
template <class T> class linkedWDigraph;template<class T>
class chain : public linearList<T>
{friend linkedDigraph;friend linkedWDigraph<int>;friend linkedWDigraph<float>;friend linkedWDigraph<double>;public:// constructor, copy constructor and destructorchain(int initialCapacity = 10);chain(const chain<T>&);~chain();// ADT methodsbool 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;// throw illegalIndex if theIndex invalidchainNode<T>* firstNode; // pointer to first node in chainint listSize; // number of elements in list
};template<class T>
chain<T>::chain(int initialCapacity)
{// Constructor.if (initialCapacity < 1){ostringstream s;s << "Initial capacity = " << initialCapacity << " Must be > 0";throw illegalParameterValue(s.str());}firstNode = NULL;listSize = 0;
}template<class T>
chain<T>::chain(const chain<T>& theList)
{// Copy constructor.listSize = theList.listSize;if (listSize == 0){// theList is emptyfirstNode = NULL;return;}// non-empty listchainNode<T>* sourceNode = theList.firstNode;// node in theList to copy fromfirstNode = new chainNode<T>(sourceNode->element);// copy first element of theListsourceNode = sourceNode->next;chainNode<T>* targetNode = firstNode;// current last node in *thiswhile (sourceNode != NULL){// copy remaining elementstargetNode->next = new chainNode<T>(sourceNode->element);targetNode = targetNode->next;sourceNode = sourceNode->next;}targetNode->next = NULL; // end the chain
}template<class T>
chain<T>::~chain()
{// Chain destructor. Delete all nodes in chain.while (firstNode != NULL){// delete firstNodechainNode<T>* nextNode = firstNode->next;delete firstNode;firstNode = nextNode;}
}template<class T>
void chain<T>::checkIndex(int theIndex) const
{// Verify that theIndex is between 0 and listSize - 1.if (theIndex < 0 || theIndex >= listSize){ostringstream s;s << "index = " << theIndex << " size = " << listSize;throw illegalIndex(s.str());}}template<class T>
T& chain<T>::get(int theIndex) const
{// Return element whose index is theIndex.// Throw illegalIndex exception if no such element.checkIndex(theIndex);// move to desired nodechainNode<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
{// Return index of first occurrence of theElement.// Return -1 if theElement not in list.// search the chain for theElementchainNode<T>* currentNode = firstNode;int index = 0; // index of currentNodewhile (currentNode != NULL && currentNode->element != theElement){// move to next nodecurrentNode = currentNode->next;index++;}// make sure we found matching elementif (currentNode == NULL)return -1;elsereturn index;
}template<class T>
void chain<T>::erase(int theIndex)
{// Delete the element whose index is theIndex.// Throw illegalIndex exception if no such element.checkIndex(theIndex);// valid index, locate node with element to deletechainNode<T>* deleteNode;if (theIndex == 0){// remove first node from chaindeleteNode = firstNode;firstNode = firstNode->next;}else { // use p to get to predecessor of desired nodechainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;deleteNode = p->next;p->next = p->next->next; // remove deleteNode from chain}listSize--;delete deleteNode;
}template<class T>
void chain<T>::insert(int theIndex, const T& theElement)
{// Insert theElement so that its index is theIndex.if (theIndex < 0 || theIndex > listSize){// invalid indexostringstream s;s << "index = " << theIndex << " size = " << listSize;throw illegalIndex(s.str());}if (theIndex == 0)// insert at frontfirstNode = new chainNode<T>(theElement, firstNode);else{ // find predecessor of new elementchainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;// insert after pp->next = new chainNode<T>(theElement, p->next);}listSize++;
}template<class T>
void chain<T>::output(ostream& out) const
{// Put the list into the stream out.for (chainNode<T>* currentNode = firstNode;currentNode != NULL;currentNode = currentNode->next)out << currentNode->element << " ";
}// overload <<
template <class T>
ostream& operator<<(ostream& out, const chain<T>& x){x.output(out); return out;}#endif
类chain数据成员:firstNode首节点
listSize元素个数
构造函数:
初始化头指针指向空,个数为0。
template<class T>
chain<T>::chain(int initialCapacity)
{// Constructor.if (initialCapacity < 1){ostringstream s;s << "Initial capacity = " << initialCapacity << " Must be > 0";throw illegalParameterValue(s.str());}firstNode = NULL;listSize = 0;
}
复制构造函数:
先将listSize复制,判断若为0则头指针指向空返回。
不为空:
sourceNode
:遍历原链表(theList
)的指针,从第一个数据节点开始,依次指向待拷贝的节点;
targetNode
:构建新链表的指针,从新链表的第一个节点开始,依次指向新创建的节点(用于链接后续节点)
(1)拷贝原链表的 “第一个数据节点”
1.让sourceNode指向原链表的第一个数据节点
2. 为新链表创建第一个数据节点(用原链表第一个节点的元素初始化)
3. sourceNode后移,指向原链表的下一个节点(准备拷贝下一个元素)
4. targetNode指向新链表的第一个节点(后续用来链接新节点)
(2)循环拷贝原链表的 “剩余节点”
1. 在targetNode后面创建新节点(用当前sourceNode的元素初始化)
2. targetNode后移,指向刚创建的新节点(准备下一次链接)
3. sourceNode后移,指向原链表的下一个待拷贝节点
template<class T>
chain<T>::chain(const chain<T>& theList)
{// Copy constructor.listSize = theList.listSize;if (listSize == 0){// theList is emptyfirstNode = NULL;return;}// non-empty listchainNode<T>* sourceNode = theList.firstNode;// node in theList to copy fromfirstNode = new chainNode<T>(sourceNode->element);// copy first element of theListsourceNode = sourceNode->next;chainNode<T>* targetNode = firstNode;// current last node in *thiswhile (sourceNode != NULL){// copy remaining elementstargetNode->next = new chainNode<T>(sourceNode->element);targetNode = targetNode->next;sourceNode = sourceNode->next;}targetNode->next = NULL; // end the chain
}
析构函数:
while循环,辅助指针nextNode,不断清除firstNode的内存。并将firstNode指向nextNode。
template<class T>
chain<T>::~chain()
{// Chain destructor. Delete all nodes in chain.while (firstNode != NULL){// delete firstNodechainNode<T>* nextNode = firstNode->next;delete firstNode;firstNode = nextNode;}
}
方法checkIndex:
template<class T>
void chain<T>::checkIndex(int theIndex) const
{// Verify that theIndex is between 0 and listSize - 1.if (theIndex < 0 || theIndex >= listSize){ostringstream s;s << "index = " << theIndex << " size = " << listSize;throw illegalIndex(s.str());}}
方法get(根据索引返回元素):
for循环,循环theIndex次,用辅助指针遍历。
template<class T>
T& chain<T>::get(int theIndex) const
{// Return element whose index is theIndex.// Throw illegalIndex exception if no such element.checkIndex(theIndex);// move to desired nodechainNode<T>* currentNode = firstNode;for (int i = 0; i < theIndex; i++)currentNode = currentNode->next;return currentNode->element;
}
方法indexOf(返回元素所在索引):
循环终止条件:找到或遍历完
template<class T>
int chain<T>::indexOf(const T& theElement) const
{// Return index of first occurrence of theElement.// Return -1 if theElement not in list.// search the chain for theElementchainNode<T>* currentNode = firstNode;int index = 0; // index of currentNodewhile (currentNode != NULL && currentNode->element != theElement){// move to next nodecurrentNode = currentNode->next;index++;}// make sure we found matching elementif (currentNode == NULL)return -1;elsereturn index;
}
方法erase(按索引清除节点):
若为第一个节点:辅助指针指向首节点,首节点指向下一节点。
否则:
1. p初始指向头节点(索引0),用于找前驱
2. 循环找到待删除节点的前驱
3. 暂存待删除节点的地址(p的下一个节点)
4. 前驱节点的next跳过待删除节点,链接后续节点
template<class T>
void chain<T>::erase(int theIndex)
{// Delete the element whose index is theIndex.// Throw illegalIndex exception if no such element.checkIndex(theIndex);// valid index, locate node with element to deletechainNode<T>* deleteNode;if (theIndex == 0){// remove first node from chaindeleteNode = firstNode;firstNode = firstNode->next;}else { // use p to get to predecessor of desired nodechainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;deleteNode = p->next;p->next = p->next->next; // remove deleteNode from chain}listSize--;delete deleteNode;
}
方法insert:
若为首节点:firstNode = new chainNode<T>(theElement, firstNode);
非头部:单链表无法直接访问 “插入位置的前一个节点”(前驱),需从表头开始遍历 theIndex-1
次,定位到前驱节点 p
—— 新节点必须插入在 p
和 p->next
之间(避免断链)。
template<class T>
void chain<T>::insert(int theIndex, const T& theElement)
{// Insert theElement so that its index is theIndex.if (theIndex < 0 || theIndex > listSize){// invalid indexostringstream s;s << "index = " << theIndex << " size = " << listSize;throw illegalIndex(s.str());}if (theIndex == 0)// insert at frontfirstNode = new chainNode<T>(theElement, firstNode);else{ // find predecessor of new elementchainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;// insert after pp->next = new chainNode<T>(theElement, p->next);}listSize++;
}
方法output与重载<<
template<class T>
void chain<T>::output(ostream& out) const
{// Put the list into the stream out.for (chainNode<T>* currentNode = firstNode;currentNode != NULL;currentNode = currentNode->next)out << currentNode->element << " ";
}// overload <<
template <class T>
ostream& operator<<(ostream& out, const chain<T>& x){x.output(out); return out;}
chainWithIterator.h(迭代器)
// linked implementation of a linear list
// derives from abstract class linearList just to make sure
// all methods of the ADT are implemented
// unidirectional iterator for chain included#ifndef chain_
#define chain_#include <iostream>
#include <sstream>
#include <string>
#include "linearList.h"
#include "chainNode.h"
#include "myExceptions.h"using namespace std;class linkedDigraph;
template <class T> class linkedWDigraph;template<class T>
class chain : public linearList<T>
{friend linkedDigraph;friend linkedWDigraph<int>;friend linkedWDigraph<float>;friend linkedWDigraph<double>;public:// constructor, copy constructor and destructorchain(int initialCapacity = 10);chain(const chain<T>&);~chain();// ADT methodsbool 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;// iterators to start and end of listclass iterator;iterator begin() {return iterator(firstNode);}iterator end() {return iterator(NULL);}// iterator for chainclass iterator {public:// typedefs required by C++ for a forward iteratortypedef forward_iterator_tag iterator_category;typedef T value_type;typedef ptrdiff_t difference_type;typedef T* pointer;typedef T& reference;// constructoriterator(chainNode<T>* theNode = NULL){node = theNode;}// dereferencing operatorsT& operator*() const {return node->element;}T* operator->() const {return &node->element;}// incrementiterator& operator++() // preincrement{node = node->next; return *this;}iterator operator++(int) // postincrement{iterator old = *this;node = node->next;return old;}// equality testingbool operator!=(const iterator right) const{return node != right.node;}bool operator==(const iterator right) const{return node == right.node;}protected:chainNode<T>* node;}; // end of iterator classprotected:void checkIndex(int theIndex) const;// throw illegalIndex if theIndex invalidchainNode<T>* firstNode; // pointer to first node in chainint listSize; // number of elements in list
};template<class T>
chain<T>::chain(int initialCapacity)
{// Constructor.if (initialCapacity < 1){ostringstream s;s << "Initial capacity = " << initialCapacity << " Must be > 0";throw illegalParameterValue(s.str());}firstNode = NULL;listSize = 0;
}template<class T>
chain<T>::chain(const chain<T>& theList)
{// Copy constructor.listSize = theList.listSize;if (listSize == 0){// theList is emptyfirstNode = NULL;return;}// non-empty listchainNode<T>* sourceNode = theList.firstNode;// node in theList to copy fromfirstNode = new chainNode<T>(sourceNode->element);// copy first element of theListsourceNode = sourceNode->next;chainNode<T>* targetNode = firstNode;// current last node in *thiswhile (sourceNode != NULL){// copy remaining elementstargetNode->next = new chainNode<T>(sourceNode->element);targetNode = targetNode->next;sourceNode = sourceNode->next;}targetNode->next = NULL; // end the chain
}template<class T>
chain<T>::~chain()
{// Chain destructor. Delete all nodes in chain.chainNode<T> *nextNode;while (firstNode != NULL){// delete firstNodenextNode = firstNode->next;delete firstNode;firstNode = nextNode;}
}template<class T>
void chain<T>::checkIndex(int theIndex) const
{// Verify that theIndex is between 0 and listSize - 1.if (theIndex < 0 || theIndex >= listSize){ostringstream s;s << "index = " << theIndex << " size = " << listSize;throw illegalIndex(s.str());}
}template<class T>
T& chain<T>::get(int theIndex) const
{// Return element whose index is theIndex.// Throw illegalIndex exception if no such element.checkIndex(theIndex);// move to desired nodechainNode<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
{// Return index of first occurrence of theElement.// Return -1 if theElement not in list.// search the chain for theElementchainNode<T>* currentNode = firstNode;int index = 0; // index of currentNodewhile (currentNode != NULL && currentNode->element != theElement){// move to next nodecurrentNode = currentNode->next;index++;}// make sure we found matching elementif (currentNode == NULL)return -1;elsereturn index;
}template<class T>
void chain<T>::erase(int theIndex)
{// Delete the element whose index is theIndex.// Throw illegalIndex exception if no such element.checkIndex(theIndex);// valid index, locate node with element to deletechainNode<T>* deleteNode;if (theIndex == 0){// remove first node from chaindeleteNode = firstNode;firstNode = firstNode->next;}else { // use p to get to predecessor of desired nodechainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;deleteNode = p->next;p->next = p->next->next; // remove deleteNode from chain}listSize--;delete deleteNode;
}template<class T>
void chain<T>::insert(int theIndex, const T& theElement)
{// Insert theElement so that its index is theIndex.if (theIndex < 0 || theIndex > listSize){// invalid indexostringstream s;s << "index = " << theIndex << " size = " << listSize;throw illegalIndex(s.str());}if (theIndex == 0)// insert at frontfirstNode = new chainNode<T>(theElement, firstNode);else{ // find predecessor of new elementchainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;// insert after pp->next = new chainNode<T>(theElement, p->next);}listSize++;
}template<class T>
void chain<T>::output(ostream& out) const
{// Put the list into the stream out.for (chainNode<T>* currentNode = firstNode;currentNode != NULL;currentNode = currentNode->next)out << currentNode->element << " ";
}// overload <<
template <class T>
ostream& operator<<(ostream& out, const chain<T>& x){x.output(out); return out;}#endif
extendedLinearList.h(扩展类,增加清除所有元素和尾插方法)
// abstract class extendedLinearList
// extends linearList by adding functions to clear and append
// all methods are pure virtual functions#ifndef extendedLinearList_
#define extendedLinearList_
#include <iostream>
#include "linearList.h"using namespace std;template<class T>
class extendedLinearList : linearList<T>
{public:virtual ~extendedLinearList() {}virtual void clear() = 0;// empty the listvirtual void push_back(const T& theElement) = 0;// insert theElement at end of list
};
#endif
extendedChain.h(增加lastNode数据成员)
// linked implementation of an extended linear list
// derives from abstract class extendedLinearList just to make sure
// all methods of the ADT are implemented
// unidirectional iterator for extendedChain included#ifndef extendedChain_
#define extendedChain_#include <iostream>
#include <sstream>
#include <string>
#include "extendedLinearList.h"
#include "chainWithIterator.h"
#include "myExceptions.h"using namespace std;template<class T>
class extendedChain : public extendedLinearList<T>, public chain<T>
{public:// constructor and copy constructorextendedChain(int initialCapacity = 10) :chain<T>(initialCapacity) {}extendedChain(const extendedChain<T>& c) :chain<T>(c) {}// ADT methodsbool empty() const {return listSize == 0;}int size() const {return listSize;}T& get(int theIndex) const{return chain<T>::get(theIndex);}int indexOf(const T& theElement) const{return chain<T>::indexOf(theElement);}void erase(int theIndex);void insert(int theIndex, const T& theElement);void clear(){// Delete all nodes in chain.while (firstNode != NULL){// delete firstNodechainNode<T>* nextNode = firstNode->next;delete firstNode;firstNode = nextNode;}listSize = 0;}void push_back(const T& theElement);void output(ostream& out) const{chain<T>::output(out);}// additional methodvoid zero(){firstNode = NULL; listSize = 0;}protected:chainNode<T>* lastNode; // pointer to last node in chain
};template<class T>
void extendedChain<T>::erase(int theIndex)
{// Delete the element whose index is theIndex.// Throw illegalIndex exception if no such element.checkIndex(theIndex);// valid index, locate node with element to deletechainNode<T>* deleteNode;if (theIndex == 0){// remove first node from chaindeleteNode = firstNode;firstNode = firstNode->next;}else { // use p to get to predecessor of desired nodechainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;deleteNode = p->next;p->next = p->next->next; // remove deleteNode from chainif (deleteNode == lastNode)lastNode = p;}listSize--;delete deleteNode;
}template<class T>
void extendedChain<T>::insert(int theIndex, const T& theElement)
{// Insert theElement so that its index is theIndex.if (theIndex < 0 || theIndex > listSize){// invalid indexostringstream s;s << "index = " << theIndex << " size = " << listSize;throw illegalIndex(s.str());}if (theIndex == 0){// insert at frontfirstNode = new chainNode<T>(theElement, firstNode);if (listSize == 0)lastNode = firstNode;}else{ // find predecessor of new elementchainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;// insert after pp->next = new chainNode<T>(theElement, p->next);if (listSize == theIndex)lastNode = p->next;}listSize++;
}template<class T>
void extendedChain<T>::push_back(const T& theElement)
{// Insert theElement at the end of the chain.chainNode<T>* newNode = new chainNode<T>(theElement, NULL);if (firstNode == NULL)// chain is emptyfirstNode = lastNode = newNode;else{ // attach next to lastNodelastNode->next = newNode;lastNode = newNode;}listSize++;
}#endif
方法erase(增加了对lastNode的维护):
template<class T>
void extendedChain<T>::erase(int theIndex)
{// Delete the element whose index is theIndex.// Throw illegalIndex exception if no such element.checkIndex(theIndex);// valid index, locate node with element to deletechainNode<T>* deleteNode;if (theIndex == 0){// remove first node from chaindeleteNode = firstNode;firstNode = firstNode->next;}else { // use p to get to predecessor of desired nodechainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;deleteNode = p->next;p->next = p->next->next; // remove deleteNode from chainif (deleteNode == lastNode)lastNode = p;}listSize--;delete deleteNode;
}
方法insert(增加了对lastNode的维护f'f):
template<class T>
void extendedChain<T>::insert(int theIndex, const T& theElement)
{// Insert theElement so that its index is theIndex.if (theIndex < 0 || theIndex > listSize){// invalid indexostringstream s;s << "index = " << theIndex << " size = " << listSize;throw illegalIndex(s.str());}if (theIndex == 0){// insert at frontfirstNode = new chainNode<T>(theElement, firstNode);if (listSize == 0)lastNode = firstNode;}else{ // find predecessor of new elementchainNode<T>* p = firstNode;for (int i = 0; i < theIndex - 1; i++)p = p->next;// insert after pp->next = new chainNode<T>(theElement, p->next);if (listSize == theIndex)lastNode = p->next;}listSize++;
}
方法push_back:
- 创建新节点:元素为
theElement
,next
为NULL
(确保是尾部节点); - 分场景接入:
- 空链表:
firstNode
和lastNode
同时指向新节点; - 非空链表:先将新节点接在当前
lastNode
后,再更新lastNode
为新节点;
- 空链表:
- 更新长度:
listSize++
,同步链表状态。
template<class T>
void extendedChain<T>::push_back(const T& theElement)
{// Insert theElement at the end of the chain.chainNode<T>* newNode = new chainNode<T>(theElement, NULL);if (firstNode == NULL)// chain is emptyfirstNode = lastNode = newNode;else{ // attach next to lastNodelastNode->next = newNode;lastNode = newNode;}listSize++;
}
二、部分习题及解答
2,3,4,5
template<class T>
void chain<T>::setSize(int theSize) {if (theSize < 0) { // 大小不能为负ostringstream s;s << "Size = " << theSize << " must be >= 0";throw illegalParameterValue(s.str());}// 原大小 > 目标大小时,删除末尾多余元素while (listSize > theSize) {erase(listSize - 1); // 从最后一个元素开始删}
}
template<class T>
void chain<T>::set(int theIndex, const T& theElement) {checkIndex(theIndex); // 检查索引是否在 [0, listSize-1]chainNode<T>* current = firstNode;for (int i = 0; i < theIndex; ++i) { // 找到目标节点current = current->next;}current->element = theElement; // 替换元素
}
4.删除一定范围节点
template<class T>
void chain<T>::removeRange(int fromIndex, int toIndex) {// 检查索引合法性if (fromIndex < 0 || toIndex >= listSize || fromIndex > toIndex) {ostringstream s;s << "Invalid range: from=" << fromIndex << ", to=" << toIndex << ", size=" << listSize;throw illegalIndex(s.str());}chainNode<T>* prev = NULL;chainNode<T>* curr = firstNode;// 找到fromIndex的前驱节点for (int i = 0; i < fromIndex; ++i) {prev = curr;curr = curr->next;}// 批量删除[fromIndex, toIndex]的节点int count = toIndex - fromIndex + 1;chainNode<T>* next;for (int i = 0; i < count; ++i) {next = curr->next;delete curr;curr = next;}// 重新连接链表(处理头节点特殊情况)if (prev == NULL) {firstNode = curr;} else {prev->next = curr;}listSize -= count;
}
template<class T>
int chain<T>::lastIndexOf(const T& theElement) const {int lastIdx = -1;chainNode<T>* curr = firstNode;int idx = 0;while (curr != NULL) {if (curr->element == theElement) {lastIdx = idx; // 记录最后一次匹配的索引}curr = curr->next;idx++;}return lastIdx;
}
6,7,8,9
template<class T>
T& chain<T>::operator[](int theIndex) {checkIndex(theIndex); // 复用已有索引检查,非法则抛 illegalIndexchainNode<T>* curr = firstNode;for (int i = 0; i < theIndex; ++i) {curr = curr->next;}return curr->element; // 返回元素引用,支持读写
}template<class T>
const T& chain<T>::operator[](int theIndex) const {checkIndex(theIndex);chainNode<T>* curr = firstNode;for (int i = 0; i < theIndex; ++i) {curr = curr->next;}return curr->element; // 常量版本,仅支持读
}
template <class T>
bool operator==(const chain<T>& x, const chain<T>& y) {if (x.listSize != y.listSize) return false; // 长度不同直接不相等chainNode<T>* nodeX = x.firstNode;chainNode<T>* nodeY = y.firstNode;while (nodeX != nullptr) {if (nodeX->element != nodeY->element) return false; // 元素不同则不相等nodeX = nodeX->next;nodeY = nodeY->next;}return true; // 所有元素都相等
}
template <class T>
bool operator!=(const chain<T>& x, const chain<T>& y) {return !(x == y); // 直接复用 == 的结果取反
}
template <class T>
bool operator<(const chain<T>& x, const chain<T>& y) {chainNode<T>* nodeX = x.firstNode;chainNode<T>* nodeY = y.firstNode;while (nodeX != nullptr && nodeY != nullptr) {if (nodeX->element < nodeY->element) return true; // x的元素更小,返回trueif (nodeX->element > nodeY->element) return false; // x的元素更大,返回falsenodeX = nodeX->next; // 元素相等,继续比较下一个nodeY = nodeY->next;}// 前缀都相等,x已空但y还有元素 → x更小;否则(都空或y空)→ x不更小return (nodeX == nullptr && nodeY != nullptr);
}
10,11,12
template<class T>
void chain<T>::swap(chain<T>& theChain) {// 交换头节点指针chainNode<T>* tempNode = firstNode;firstNode = theChain.firstNode;theChain.firstNode = tempNode;// 交换链表长度int tempSize = listSize;listSize = theChain.listSize;theChain.listSize = tempSize;
}
template<class T>
chain<T> arrayListToChain(const arrayList<T>& arrList) {chain<T> result;int n = arrList.size();for (int i = 0; i < n; ++i) {result.insert(i, arrList.get(i));}return result;
}
template<class T>
arrayList<T> chainToArray1(const chain<T>& ch) {arrayList<T> result;int n = ch.size();for (int i = 0; i < n; ++i) {result.insert(i, ch.get(i));}return result;
}
template<class T>
arrayList<T> chainToArray2(const chain<T>& ch) {arrayList<T> result;typename chain<T>::iterator it = ch.begin();int i = 0;while (it != ch.end()) {result.insert(i++, *it);++it;}return result;
}
13.
// 1. fromList:将数组线性表 theList 转换为当前链表void fromList(const arrayList<T>& theList) {// 先清空当前链表(删除所有现有元素)while (!empty()) {erase(0);}int n = theList.size(); // 数组线性表的元素个数for (int i = 0; i < n; ++i) {insert(i, theList.get(i)); // 逐个插入数组元素到链表}}// 2. toList:将当前链表转换为数组线性表 theListvoid toList(arrayList<T>& theList) const {// 先清空目标数组线性表while (!theList.empty()) {theList.erase(0);}int n = listSize; // 当前链表的元素个数for (int i = 0; i < n; ++i) {theList.insert(i, get(i)); // 逐个获取链表元素插入到数组}}
14.
template <class T>
inline void chain<T>::leftShift(int i)
{if (i < 0 || i > listSize) {ostringstream s;s << "左移位数 i = " << i << " 无效,链表当前大小为 " << listSize;throw illegalIndex(s.str());}for (int j = 0; j < i; ++j) {erase(0);}
}
15,16
template<class T>
void chain<T>::reverse() {if (listSize <= 1) return; // 空或单元素链表无需反转chainNode<T>* prev = NULL; // 前一个节点(初始为NULL,对应新尾节点)chainNode<T>* curr = firstNode; // 当前节点chainNode<T>* next; // 下一个节点的临时存储while (curr != NULL) {next = curr->next; // 保存下一个节点curr->next = prev; // 反转当前节点的next指针prev = curr; // 移动prev到当前节点curr = next; // 移动curr到下一个节点}firstNode = prev; // 最后prev指向原链表的尾节点,作为新的头节点
}
16:新建一个空链表,从原链表尾部向头部依次取元素插入新链表头部,最后复制新链表到原链表。
template<class T>
void reverseChain(chain<T>& c) {chain<T> temp;int n = c.size();// 从原链表最后一个元素开始,依次插入到temp的头部for (int i = n - 1; i >= 0; --i) {temp.insert(0, c.get(i));}// 清空原链表并复制temp的内容while (!c.empty()) {c.erase(0);}for (int i = 0; i < n; ++i) {c.insert(i, temp.get(i));}
}
17,18
template <class T>
extendedChain<T> meld(const extendedChain<T>& a, const extendedChain<T>& b) {extendedChain<T> c;int i = 0, j = 0;bool takeA = true;while (i < a.size() || j < b.size()) {if (takeA && i < a.size()) {c.insert(c.size(), a.get(i)); // 取a的元素,插入到c末尾i++;} else if (j < b.size()) {c.insert(c.size(), b.get(j)); // 取b的元素,插入到c末尾j++;}takeA = !takeA; // 切换取a/b的标记}return c;
}
template <class T>
void chain<T>::meld(chain<T>& a, chain<T>& b) {// 清空当前链表while (!empty()) erase(0);chainNode<T> *currA = a.firstNode, *currB = b.firstNode;chainNode<T> *prev = nullptr, *newNode;bool takeA = true;// 交替拼接a和b的节点while (currA || currB) {if (takeA && currA) {newNode = currA;currA = currA->next;} else if (currB) {newNode = currB;currB = currB->next;} else break;if (!prev) firstNode = newNode; // 处理第一个节点else prev->next = newNode;prev = newNode;takeA = !takeA;}// 拼接剩余节点(若a或b还有剩余)prev->next = currA ? currA : currB;// 更新长度 & 置空a、blistSize = a.listSize + b.listSize;a.firstNode = b.firstNode = nullptr;a.listSize = b.listSize = 0;
}
19,20
类似 “归并排序” 的合并阶段:同时遍历两个有序链表,每次选较小的元素插入新链表,最后拼接剩余元素。
template <class T>
extendedChain<T> merge(const extendedChain<T>& a, const extendedChain<T>& b) {extendedChain<T> c;int i = 0, j = 0;// 同时遍历a和b,选较小元素插入cwhile (i < a.size() && j < b.size()) {if (a.get(i) < b.get(j)) {c.insert(c.size(), a.get(i++));} else {c.insert(c.size(), b.get(j++));}}// 拼接a的剩余元素while (i < a.size()) c.insert(c.size(), a.get(i++));// 拼接b的剩余元素while (j < b.size()) c.insert(c.size(), b.get(j++));return c;
}
直接操作节点指针,交替 “摘取”a
/b
的节点拼接到当前链表,合并后清空 a
和 b
。
template <class T>
void chain<T>::merge(chain<T>& a, chain<T>& b) {while (!empty()) erase(0); // 清空当前链表chainNode<T> *currA = a.firstNode, *currB = b.firstNode, *prev = nullptr;while (currA && currB) {chainNode<T>* node;// 选较小的节点if (currA->element < currB->element) {node = currA;currA = currA->next;} else {node = currB;currB = currB->next;}// 接入当前链表if (!prev) firstNode = node;else prev->next = node;prev = node;node->next = nullptr;}// 拼接剩余节点prev->next = currA ? currA : currB;// 更新长度并清空a、blistSize = a.listSize + b.listSize;a.firstNode = b.firstNode = nullptr;a.listSize = b.listSize = 0;
}
21,22
第 21 题:非成员方法 split
(复制元素生成新链表)
实现逻辑
遍历原链表 c
,按索引奇偶性,将元素分别复制到新链表 a
(奇数索引)和 b
(偶数索引),不修改原链表 c
。
template <class T>
void split(extendedChain<T>& a, extendedChain<T>& b, const extendedChain<T>& c) {// 清空a和b,避免原有元素干扰while (!a.empty()) a.erase(0);while (!b.empty()) b.erase(0);int n = c.size();for (int i = 0; i < n; ++i) {if (i % 2 == 1) { // 奇数索引(从0开始),放入aa.insert(a.size(), c.get(i));} else { // 偶数索引,放入bb.insert(b.size(), c.get(i));}}
}
第 22 题:成员方法 chain<T>::split
(复用原节点生成链表)
实现逻辑
直接操作原链表(*this
)的节点,拆分到 a
和 b
,拆分后原链表被清空(节点 “转移” 到 a
、b
)。
template <class T>
void chain<T>::split(chain<T>& a, chain<T>& b) {// 1. 清空目标链表a和b(避免原有元素干扰)while (!a.empty()) a.erase(0);while (!b.empty()) b.erase(0);chainNode<T> *curr = firstNode; // 指向当前链表的当前节点chainNode<T> *aTail = nullptr; // 记录a的尾节点(用于拼接)chainNode<T> *bTail = nullptr; // 记录b的尾节点int index = 0; // 当前元素的索引(从0开始)// 2. 遍历当前链表的所有节点while (curr != nullptr) {chainNode<T> *next = curr->next; // 暂存下一个节点(防止断链后丢失)curr->next = nullptr; // 断开当前节点与原链表的连接// 3. 根据索引奇偶性,将节点加入a或bif (index % 2 == 1) { // 奇数索引 → 加入aif (a.empty()) { // a为空时,设置a的头节点a.firstNode = curr;aTail = curr;} else { // a非空时,拼到a的尾部aTail->next = curr;aTail = curr;}a.listSize++; // 更新a的长度} else { // 偶数索引 → 加入bif (b.empty()) { // b为空时,设置b的头节点b.firstNode = curr;bTail = curr;} else { // b非空时,拼到b的尾部bTail->next = curr;bTail = curr;}b.listSize++; // 更新b的长度}curr = next; // 移动到原链表的下一个节点index++; // 索引+1}// 4. 清空当前链表(*this)firstNode = nullptr;listSize = 0;
}
23.
要实现循环右移操作,核心思路是找到 “断点” 节点,将链表拆分为两部分后重新连接。
循环右移 i
位 = 把链表的后 i
个元素 “搬到最前面”,剩下的前半部分接在后面。
template <class T>
void extendedChain<T>::circularShift(int i) {int n = listSize;if (n <= 1) return; // 空链表或单元素,无需移动// 处理i的范围:取模转为有效偏移(0 ≤ i < n)i = i % n;if (i < 0) i += n;if (i == 0) return; // 偏移0,无需操作// 步骤1:找到第 n-i 个节点(它的下一个节点将成为新头)chainNode<T>* prev = firstNode;for (int j = 0; j < n - i - 1; ++j) {prev = prev->next;}// 步骤2:记录新头、原尾,并重组链表chainNode<T>* newFirst = prev->next; // 新头是第 n-i 个节点的下一个chainNode<T>* tail = newFirst; // 找原链表的尾节点while (tail->next != nullptr) {tail = tail->next;}tail->next = firstNode; // 原尾连原头,形成临时循环prev->next = nullptr; // 断开原链表,新头的前驱置空firstNode = newFirst; // 更新头节点
}