博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【指针】基于单向链表的list(待改进)
阅读量:5908 次
发布时间:2019-06-19

本文共 9674 字,大约阅读时间需要 32 分钟。

Description:

 请实现以下基于单向链表的list类

enum Error_code{         success,         underflow,         overflow};template 
struct 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;};
View Code

 

 

解题思路:

首先,对于一个普通的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};template
struct 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; }};
View Code

 

 

 

 

 

 

进一步思考:

这里,我们不妨再看看,常常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};template
struct 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; }};
View Code

 

 

 

总结:

也许你觉得这不过是少了十几行代码,少了两段if语句,但下一篇,双向链表,我们能更进一步看见这种方法的安全性和便捷性。

 

转载于:https://www.cnblogs.com/zengyh-1900/p/4067679.html

你可能感兴趣的文章
hbase分布式集群搭建
查看>>
ASP.NET Core 2.0 : 六. 举个例子来聊聊它的依赖注入
查看>>
VidLoc: A Deep Spatio-Temporal Model for 6-DoF Video-Clip Relocalization
查看>>
盗墓笔记——路由器密码破解
查看>>
akka---Getting Started Tutorial (Java): First Chapter
查看>>
python 统计单词个数
查看>>
虚拟机VirtualBox 5.1.0|VBOX
查看>>
目前机器学习和深度学习能做些什么?
查看>>
基于html5 canvas和js实现的水果忍者网页版
查看>>
深入理解javascript描述元素内容的5个属性
查看>>
Android 知识梳理
查看>>
【反射】使用反射来获取注解原数据信息-类信息-方法信息等
查看>>
【原创】宿主机远程登录虚拟机(windows server 2003系统)
查看>>
前端开发,关于图片的那些事
查看>>
如何合理的规划jvm性能调优
查看>>
从地址字符串获取省市区信息
查看>>
莫比乌斯反演初步与实际应用
查看>>
技术分享:阿里巴巴Dubbo实现的源码分析
查看>>
Redis3.2源码分析-跳跃表zskiplist
查看>>
开发人员可以提高效率的chrome插件推荐
查看>>