请实现以下基于单向链表的list类
enum Error_code{ success, underflow, overflow};templatestruct Node{ List_entry entry; Node *next;}; template class MyList{public: MyList(); ~MyList(); // 拷贝构造函数和赋值运算符重载,注意深拷贝与浅拷贝的差异 MyList(const MyList ©); void operator =(const MyList ©); // 清空list void clear(); // 判断list是否为空 bool empty() const; // 判断list是否已满 bool full() const; // 获取list的元素数量 int size() const; // 在第position个位置插入值为entry的元素,如果position为0则插入在链表头,依次类推 // 若position < 0 或者 position > count,则返回underflow Error_code insert(int position, const List_entry &entry); // 删除第position个位置的元素,并将该元素的值保存在entry中 // 若position < 0 或者 position >= count,则返回underflow Error_code remove(int position, List_entry &entry); // 获取第position个位置的元素,保存在entry中 // 若position < 0 或者 position >= count,则返回underflow Error_code retrieve(int position, List_entry &entry) const; // 将第position个位置的元素替换为entry // 若position < 0 或者 position >= count,则返回underflow Error_code replace(int position, const List_entry &entry); // 用visit函数遍历list内所有的元素 void traverse(void (*visit)(List_entry &));protected: int count; // 记录list内元素数量 Node *head; // 链表头指针 mutable int curPosition; // current指针的位置编号 mutable Node *current; // current指针 // 设置current指针的位置,指向第position个位置 void setPosition(int position) const;};
解题思路:
首先,对于一个普通的list来说,最基本的不外乎增删查改,其他的赋值或清空都可以通过这4种操作来完成,写好这主要的4个函数就好了。
另外,注意到这个MyList类提供了current这个指针。
1.insert(增):
position合理的情况下,若position为队头,则直接将position的next指向head,head再更新;
若position不是队头,position的next指向下一个位置,前一个节点的next指向position;
2.remove(删):
position合理的情况下,若删除位置为队头,head=head->next,并注意将原本的队头delete;
若删除位置不是队头,则前节点直接指向potision的后节点,position节点delete即可;
3.retrieve(查):
调用setPosition来查找目标,并返回值即可;
4.replace(改):
调用setPosition查找目标,并修改值;
5.赋值运算:
不断从copy中读取(retrieve),并插入(insert)到MyList中;
6.clear(清空):
可以不断调用remove来清空,这里代码我就直接用for循环来删除啦。
7.setPosition:是通过current指针来提高平均时间复杂度的一个函数;
当position比current大时,current只需向后更新;
若position小于current时,则current先更新为head,然后再更新到position位置
实现代码:
enum Error_code//错误信息{ success, underflow, overflow};templatestruct Node{ List_entry entry; Node *next;};template class MyList{ public: MyList() { curPosition = count = 0; head = current = 0; } ~MyList() { clear(); } // 拷贝构造函数和赋值运算符重载 MyList(const MyList ©) { curPosition = count = 0;//拷贝构造函数一定要对数据成员进行初始化! head = current = 0; *this = copy; } void operator=(const MyList ©) { clear(); List_entry entry; for (count = 0; count < copy.size(); ) { copy.retrieve(count, entry);//读取 insert(count, entry); //增加 } setPosition(copy.curPosition); } // 清空list void clear() { Node * tmp1 = head; Node * tmp2; while (tmp1 != 0) { tmp2 = tmp1->next; delete tmp1; tmp1 = tmp2; } count = curPosition = 0; current = head = 0; } // 判断list是否为空 bool empty() const { if (count == 0) return true; else return false; } // 判断list是否已满 bool full() const { return false; } // 获取list的元素数量 int size() const { return count; } // 在第position个位置插入值为entry的元素,如果position为0则插入在链表头,依次类推 // 若position < 0 或者 position > count,则返回underflow Error_code insert(int position, const List_entry& entry) { // if (position < 0 || position > count) return underflow; else { count++; Node * tmp = new Node ; tmp->entry = entry; if (position == 0) { if (head == 0) { //在队头增加 tmp->next = head; head = tmp; } current = head; } else { //在list中间增加 setPosition(position-1); tmp->next = current->next; current->next = tmp; current = tmp; curPosition++; } } return success; } // 删除第position个位置的元素,并将该元素的值保存在entry中 // 若position < 0 或者 position >= count,则返回underflow Error_code remove(int position, List_entry &entry) { if (position < 0 || position >= count) return underflow; else { count--; if (position == 0) //删队头 { Node * tmp= head; entry = tmp->entry; head= head->next; delete tmp; current = head; curPosition = 0; } else { //删除list中的元素 setPosition(position-1); Node * tmp = current->next; entry = tmp->entry; current->next = tmp->next; delete tmp; } return success; } } // 获取第position个位置的元素,保存在entry中 // 若position < 0 或者 position >= count,则返回underflow Error_code retrieve(int position, List_entry& entry) const { if (position < 0 || position >= count) return underflow; else { setPosition(position); entry = current->entry; return success; } } // 将第position个位置的元素替换为entry // 若position < 0 或者 position >= count,则返回underflow Error_code replace(int position, const List_entry &entry) { if (position < 0 || position >= count) return underflow; else { setPosition(position); current->entry = entry; return success; } } // 用visit函数遍历list内所有的元素 void traverse(void(*visit)(List_entry&)) { Node * tmp = head; for (int i = 0; i < count; i++) { (*visit)(tmp->entry); tmp = tmp ->next; } } protected: int count; // 记录list内元素数量 Node *head; // 链表头指针 mutable int curPosition; // current指针的位置编号 mutable Node * current; // current指针 // 设置current指针的位置,指向第position个位置 void setPosition(int position) const { if (position >= curPosition) for (; curPosition < position; curPosition++) current = current->next; else for (current = head, curPosition = 0; curPosition < position; curPosition++) current = current->next; }};
进一步思考:
这里,我们不妨再看看,常常runtime error让我们头疼的链表问题是非法访问内存地址,
比如,队列为空时,head==0,但我们常常不小心访问了head->next,或者企图访问head的前节点
而这个情况常常发生在增删的情况中,那我们可以使list初始情况就为非空
令head永远指向一个空节点node(node->next=0),初始情况curPosition=-1,
这样每次插入新元素,不管新元素的位置在哪里,都不用再做特殊判断,直接更新position前节点的next即可
也就是插入新元素只有以下这两种情况:
和
而这两种情况的实现代码都是:setPosition(position-1);
tmp->next = current->next;
current->next = tmp;
每次删除新元素,也不用管是不是队头,直接更新前节点的next即可
也就是删除新元素只有以下这两种情况:
而这两种情况的实现代码都是:Node<List_entry>* tmp = current->next;
current->next = tmp->next;
delete tmp;
实现代码:
/*有空队头的情况*/enum Error_code//错误信息{ success, underflow, overflow};templatestruct Node{ List_entry entry; Node *next;};template class MyList{ public: MyList() { count = 0; curPosition = -1; head = current = new Node ; head->next = 0; } ~MyList() { clear(); delete head; head = current = 0; count = curPosition = 0; } // 拷贝构造函数和赋值运算符重载 MyList(const MyList ©) { count = 0;//拷贝构造函数一定要对数据成员进行初始化! curPosition = -1; head = current = new Node ; head->next = 0; *this = copy; } void operator=(const MyList ©) { clear(); List_entry entry; while(count < copy.size()) { copy.retrieve(count, entry);//读取 insert(count, entry);//增加 } setPosition(copy.curPosition); } // 清空list void clear() { Node * tmp1 = head->next; Node * tmp2; while (tmp1 != 0) { tmp2 = tmp1->next; delete tmp1; tmp1 = tmp2; } count = 0; current = head; head->next = 0; curPosition = -1; } // 判断list是否为空 bool empty() const { if (count == 0) return true; else return false; } // 判断list是否已满 bool full() const { return false; } // 获取list的元素数量 int size() const { return count; } // 在第position个位置插入值为entry的元素,如果position为0则插入在链表头,依次类推 // 若position < 0 或者 position > count,则返回underflow Error_code insert(int position, const List_entry& entry) { if (position < 0 || position > count) return underflow; else { Node * tmp = new Node ; tmp->entry = entry; setPosition(position-1); tmp->next = current->next; current->next = tmp; current = tmp; curPosition++; count++; } return success; } // 删除第position个位置的元素,并将该元素的值保存在entry中 // 若position < 0 或者 position >= count,则返回underflow Error_code remove(int position, List_entry &entry) { if (position < 0 || position >= count) return underflow; else { setPosition(position-1); Node * tmp = current->next; entry = tmp->entry; current->next = tmp->next; delete tmp; count--; return success; } } // 获取第position个位置的元素,保存在entry中 // 若position < 0 或者 position >= count,则返回underflow Error_code retrieve(int position, List_entry& entry) const { if (position < 0 || position >= count) return underflow; else { setPosition(position); entry = current->entry; return success; } } // 将第position个位置的元素替换为entry // 若position < 0 或者 position >= count,则返回underflow Error_code replace(int position, const List_entry &entry) { if (position < 0 || position >= count) return underflow; else { setPosition(position); current->entry = entry; return success; } } // 用visit函数遍历list内所有的元素 void traverse(void(*visit)(List_entry&)) { Node * tmp = head->next; for (int i = 0; i < count; i++) { (*visit)(tmp->entry); tmp = tmp ->next; } } protected: int count;// 记录list内元素数量 Node *head;// 链表头指针 mutable int curPosition;// current指针的位置编号 mutable Node * current;// current指针 // 设置current指针的位置,指向第position个位置 void setPosition(int position) const { if (position >= curPosition) for (; curPosition < position; curPosition++) current = current->next; else for (current = head, curPosition = -1; curPosition < position; curPosition++) current = current->next; }};
总结:
也许你觉得这不过是少了十几行代码,少了两段if语句,但下一篇,双向链表,我们能更进一步看见这种方法的安全性和便捷性。