链表
来源:互联网 发布:网络推广文案案例 编辑:程序博客网 时间:2024/06/05 15:53
转自:http://blog.csdn.net/u012175089/article/details/54231845?locationNum=7&fps=1
跟Vector一样,我自己也写了一个简单的List来进行研究。
这里实现的是双向链表,因为双向链表包含了单向链表的所以功能,所以就没有单独写一个了。
这个双向链表的实现,在创建的时候,就已经有了两个节点,分别是head和tail。这是抽离出来,不存放数据的节点,是为了让程序简化,被称为哨兵节点。
假如不使用哨兵节点,在表头表尾操作的插入删除的时候,有很多要特殊处理的地方。
加了着两个节点,就可以大大简化这些特殊操作。数据上的表头不再试实际代码的表头。
[cpp] view plain copy
- //
- // List.h 双向链表的实现
- // HelloWorld
- // csdn blog:http://blog.csdn.net/u012175089
- // Created by feiyin001 on 17/1/7.
- // Copyright (c) 2017年 FableGame. All rights reserved.
- //
- #ifndef __HelloWorld__List__
- #define __HelloWorld__List__
- namespace Fable
- {
- //双向链表,使用模板
- template<typename Object>
- class List
- {
- private:
- //节点,只在List内部使用,所有在私有区域内声明
- struct Node
- {
- Object data;//链表内的有效数据
- Node* prev;//指向前一个数据
- Node* next;//指向下一个数据
- Node(const Object& d = Object(), Node* p = nullptr, Node* n = nullptr): data(d),prev(p),next(n){}
- };
- public:
- //const的迭代器
- class const_iterator
- {
- public:
- //默认构造函数
- const_iterator():current(nullptr){}
- //获得Object对象
- const Object& operator*()const
- {
- return retrieve();
- }
- //自增,前缀自增
- const_iterator& operator++()
- {
- current = current->next;
- return *this;
- }
- //自增,后缀自增,这里的int只是作为一种标志来使用,并没有什么卵用
- const_iterator operator++(int)
- {
- const_iterator old = *this;//原来的数据
- ++(*this);//调用前缀版本的自增
- return old;//返回原来的数据
- }
- //自减,前缀自增
- const_iterator& operator--()
- {
- current = current->prev;
- return *this;
- }
- //自减,后缀自减,这里的int只是作为一种标志来使用,并没有什么卵用
- const_iterator operator--(int)
- {
- const_iterator old = *this;//原来的数据
- --(*this);//调用前缀版本的自增
- return old;//返回原来的数据
- }
- //==重载
- bool operator==(const const_iterator& rhs) const
- {
- return current == rhs.current;
- }
- //!=重载
- bool operator!=(const const_iterator& rhs)const
- {
- return !(*this == rhs);
- }
- protected:
- const List<Object> * theList;//把列表传了进来,作为检测的时候使用的
- Node* current;//迭代器所指向的结点
- //获得结点的数据,方便给子类使用
- Object& retrieve()const
- {
- return current->data;
- }
- void assertIsValid()const//检测指针是否合法
- {
- if (!theList || !current || current == theList->head)//检测列表为空,当前指针为空,当前在头结点
- {
- throw ("IteratorOutOfBoundsException");//抛出异常,这里应该使用Exception相关类
- }
- }
- //构造函数
- const_iterator(const List<Object>& lst, Node* p):theList(&lst), current(p){}
- //友元类,方便在List中访问
- friend class List<Object>;
- };
- //迭代器
- class iterator: public const_iterator
- {
- public:
- iterator(){}//默认构造函数
- //*重载
- Object& operator*()
- {
- //return retrieve();无法通过编译
- return this->retrieve();//也可以用域作用符
- }
- //*重载
- const Object& operator*()const
- {
- return const_iterator::operator*();//调用父类函数
- }
- //自增,前缀
- iterator operator++()
- {
- //current = current->next;无法通过编译
- this->current = this->current->next;//也可以用域作用符
- return *this;
- }
- //自增,后缀
- iterator operator++(int)
- {
- iterator old = *this;
- ++(*this);
- return old;
- }
- //自减,前缀
- iterator operator--()
- {
- this->current = this->current->prev;//也可以用域作用符
- return *this;
- }
- //自减,后缀
- iterator operator--(int)
- {
- iterator old = *this;
- --(*this);
- return old;
- }
- //==重载
- bool operator==(const iterator& rhs) const
- {
- return this->current == rhs.current;
- }
- //!=重载
- bool operator!=(const iterator& rhs)const
- {
- return !(*this == rhs);
- }
- protected:
- //构造函数,list内部调用的
- iterator(const List<Object>& lst, Node* p) :const_iterator (lst, p){}
- //友元类
- friend class List<Object>;
- };
- public:
- //默认构造函数
- List()
- {
- init();//初始化
- }
- //复制构造函数
- List(const List& rhs)
- {
- init();
- *this = rhs;
- }
- //析构函数
- ~List()
- {
- clear();//清空链表
- //释放掉两个指针的内存
- delete head;
- delete tail;
- }
- //复制赋值运算符
- const List& operator=(const List& rhs)
- {
- //如果是相同的地址,就不用复制了。
- if (this == &rhs)
- {
- return *this;
- }
- clear();//清空当前的链表
- //按顺序一个一个复制进链表中
- for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter)
- {
- push_back(*iter);
- }
- return *this;
- }
- //获取第一个迭代器
- iterator begin()
- {
- return iterator(*this, head->next);//head是不存放数据的
- }
- //获取第一个数据的迭代器
- const_iterator begin() const
- {
- return const_iterator(*this, head->next);//head是不存放数据的
- }
- //获取最后一个迭代器
- iterator end()
- {
- return iterator(*this, tail);//在STL里面,end返回的是超界地址,而不是最后一个数据的地址,这里是tail
- }
- const_iterator end()const
- {
- return const_iterator(tail);//在STL里面,end返回的是超界地址,而不是最后一个数据的地址,这里是tail
- }
- //获得链表的大小
- int size()const
- {
- return theSize;
- }
- //是否为空链表
- bool empty()const
- {
- return theSize == 0;
- }
- //清空整个列表
- void clear()
- {
- while (!empty())
- {
- pop_front();//一个一个从表头开始删除。
- }
- }
- //第一个数据的迭代器
- Object& front()
- {
- return *begin();
- }
- //第一个数据的迭代器
- const Object& front()const
- {
- return *begin();
- }
- //最后一个数据的迭代器。
- Object& back()
- {
- return *(--end());//end()返回的是超界迭代器,所以要自减才能获得最后一个数据
- }
- //在表头插入数据
- void push_front(const Object& x)
- {
- insert(begin(), x);//因为head和tail都是不放数据的,所以无论在哪里插入,都是指定表中的位置插入数据
- }
- //在表尾插入收据
- void push_back(const Object& x)
- {
- insert(end(), x);
- }
- //弹出最开始的数据
- void pop_front()
- {
- erase(begin());
- }
- //弹出最后的数据
- void pop_back()
- {
- erase( --end() );
- }
- //在迭代器的位置插入数据
- iterator insert(iterator iter, const Object& x)
- {
- iter.assertIsValid();//检测迭代器是否合法
- if (iter.theList != this)//检测是否同一个链表的
- {
- throw ("IteratorMismatchException");
- }
- Node* p = iter.current;//当前的指针,会被压后一个
- theSize++;//链表大小+1
- //p的前一个指针是新的节点,p的原来的前一个指针的后一个指针指向新的节点。
- return iterator(*this, p->prev = p->prev->next = new Node(x, p->prev, p));//构建新的指针
- }
- //erase函数,删除迭代器指向的节点,这个很重要,具体的实现,决定了for循环中删除数据的写法。
- iterator erase(iterator iter)
- {
- Node* p = iter.current;
- iterator retVal(*this, p->next);
- p->prev->next = p->next;
- p->next->prev = p->prev;
- delete p;//这个写法里面,P指向的节点已经被删除了,
- theSize--;//减少一
- return retVal;//返回的是下一个指针。
- }
- //删除区间内的节点
- iterator erase(iterator start, iterator end)
- {
- for (iterator iter = start ; iter!= end; )
- {
- iter = erase(iter);//删除之后,返回的是下一个数据,所以这个for循环里面,是不需要iter++的。
- }
- }
- private:
- int theSize;
- Node* head;
- Node* tail;
- //初始化,把构造函数里面的内容抽出来
- void init()
- {
- //创建了两个节点,把节点指针互相指向,这是一个空链表
- theSize = 0;
- head = new Node;
- tail = new Node;
- head->next = tail;//指向结尾
- tail->prev = head;
- }
- };
- }
- #endif /* defined(__HelloWorld__List__) */
估计还有很多很多地方是没有实现的,例如异常检测,还是少了点。
不过可以大致看到原理。
再写个简单的测试程序:
[cpp] view plain copy
- //
- // List.cpp
- // HelloWorld
- // csdn blog:http://blog.csdn.net/u012175089
- // Created by feiyin001 on 17/1/7.
- // Copyright (c) 2017年 FableGame. All rights reserved.
- //
- #include "List.h"
- #include <iostream>
- using namespace Fable;
- int main(int argc, char* argv[])
- {
- List<int> li;
- for (int i = 0; i < 100; i++)
- {
- li.push_back(i);
- }
- for ( List<int>::iterator iter = li.begin(); iter != li.end(); )
- {
- if (*iter % 3 == 0)
- {
- iter = li.erase(iter);
- }
- else
- {
- std::cout << *iter << std::endl;
- ++iter;
- }
- }
- return 0;
- }
阅读全文
0 0
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 链表
- 浅谈javascirt this机制
- 【HDU1698】【模板】Just a Hook
- python多版本时候pip安装时候要添加目录
- ZJCOJ: L先生与质数V4(数论)
- tomcat搭建https服务器+阿里云免费证书
- 链表
- map 数组里放 pair 或 结构体
- 找到一本不错的Linux电子书,附《Linux就该这么学》章节目录。
- 用 travis-ci 自动部署 github 上的 angular2 项目到 centos7 的 vps
- hibernate-组件映射-9
- 为什么下一个5年java后台开发你该选择Spring Boot?
- VC版双人PK版俄罗斯方块
- maven构建多模块
- BOM基础