单向链表-slist
博主所分享的这个单向链表slist,是依据侯捷老师的《STL源码解析》中slist一节的slist,因为博主在跑书上slist上的例子时,发现#include <slist> <script type="math/tex" id="MathJax-Element-51"> </script>报错,编译器并没有提供slist这个库,所以自己就依照书上的代码,照葫芦画瓢自己实现了一个简单的slist。这里slist主要由节点、迭代器以及slist本身的数据结构组成。
节点的定义
节点的定义如下,定义在nodeStruct.h的头文件中:
//nodeStruct.h
template<class T>
struct nodeStruct{
T data;
nodeStruct* next;
};
slist迭代器的定义
迭代器的定义如下,定义在slist_iterator.h的头文件中:
//slist_iterator.h
#include "nodeStruct.h"
template<class T,class Ref,class Ptr>
class iterator_{
typedef iterator_<T, T&, T*> iterator;
typedef iterator_<T, const T&, const T*> const_iterator;
typedef iterator_<T, Ref, Ptr> self;
typedef T value_type;
typedef Ref reference;
typedef Ptr pointer;
typedef nodeStruct<T> node;
public:
node* nnn;//定义一个node节点
public:
iterator_(node* x) :nnn(x){}//构造函数
iterator_() : nnn(0){}//构造函数
iterator_(const iterator& iter) :nnn(iter.nnn){}//拷贝构造函数
//重载等号运算符
self& operator=(const iterator& iter)
{
nnn = iter.nnn;
return *this;
}
//判断两个迭代器是否相等
bool operator==(const iterator& iter)
{
return nnn == iter.nnn;
}
//判断两个迭代器是否不相等
bool operator!=(const iterator& iter)
{
return nnn != iter.nnn;
}
//迭代器自增
self& operator++()
{
nnn = nnn->next;
return *this;
}
//迭代器自增
self operator++(int)
{
self tmp = *this;
++(*this);
return tmp;
}
//重载+=运算符
self operator+=(int n)
{
while (n-- > 0)
{
if (nnn == 0)
return iterator(0);
nnn = nnn->next
}
return *this;
}
//重载*运算符,获取数据
reference operator*()
{
return nnn->data;
}
//重载->运算符,获取数据的地址
pointer operator->()
{
return &(operator*());
}
};
slist数据结构的定义
数据结构的定义如下,定义在slist.h的头文件中:
//slist.h
#include "slist_iterator.h"
template<class T>
class slist{
typedef T value_type;
typedef value_type& reference;
typedef const reference const_reference;
typedef value_type* pointer;
typedef const pointer const_pointer;
typedef nodeStruct<T> node;
private:
node* head;//设置一个头结点
public:
typedef iterator_<T, T&, T*> iterator;
typedef iterator_<T, const T&, const T*> const_iterator;
//构造函数初始化,将头结点head的数据域data设置为0,指针域next设置为0
//头指针不存储任何有用的数据,仅仅是为了方便数据的运算操作而出现的
slist(){
head = new node();
head->data = 0;
head->next = 0;
}
//析构函数,使用完slist后,释放每个节点的内存
~slist(){
node* tmp = head->next;
while (tmp != 0)
{
node* next = tmp->next;
delete tmp;
tmp = next;
}
}
//向链表slist中插入节点,新节点一般插入到头结点head的后面,所以节点的插入
//的顺序与它在链表中的顺序是相反的
void push_front(reference val)
{
//node* pn = (node*)(malloc(sizeof(node)));
node* pn = new node();
pn->data = val;
pn->next = head->next;
head->next = pn;
}
//将头节点之后的第一个节点清除掉
void pop_front()
{
if (head->next != 0)
{
node* pn = head->next;
head->next = pn->next;
delete pn;
}
}
//获取slist中节点的个数,不包含头结点
size_t size() const
{
size_t size=0;
if (head->next == 0)
{
return 0;
}
node* tmp = head->next;
while (tmp != 0)
{
size++;
tmp = tmp->next;
}
return size;
}
//交换两个slist
void swap(slist& L)
{
node* tmp = head->next;
L.head->next = tmp;
head->next = L.head->next;
}
//判断目前slist是否含有节点,不包含头结点
bool empty()const
{
return head->next == 0;
}
//从头结点后的第一个节点开始,依次展示slist中存储的所有数据
void showList()const
{
node* tmp = head->next;
while (tmp != 0)
{
cout << tmp->data << ' ';
tmp = tmp->next;
}
cout << endl;
}
//获取slist开始的迭代器
iterator begin()
{
return iterator(head->next);
}
//获取slist结束的迭代器
iterator end()
{
return iterator(0);
}
//向slist中的某个位置之前插入节点,通过迭代器来完成
iterator insert(iterator& iter, value_type val)
{
iterator beg = begin();
while(beg != end())
{
iterator next = beg;
++next;
if (next == iter)
{
node* tmp = new node();
tmp->data = val;
tmp->next = (beg.nnn)->next;
(beg.nnn)->next = tmp;
return iterator(tmp);返回当前插入位置的迭代器
}
beg = next;
}
return beg;//如果没有找到要插入的位置,返回最后一个节点所表示的迭代器
}
//将slist中某个位置的节点删除,通过迭代器来完成,返回所删除节点指向的下一
//个节点所表示的迭代器
iterator erase(iterator& iter)
{
iterator beg = begin();
while (beg != end())
{
iterator next = beg;
++next;
if (next == iter)
{
(beg.nnn)->next = (iter.nnn)->next;
delete iter.nnn;
return ++beg;
}
beg = next;
}
return beg;
}
};
至此,简单的slist的已经完成,下面我们来做一小下测试:
//slistTest.h
#include "slist.h"
using namespace std;
int main(){
slist<int> li;
for (int i = 0; i < 10; i++)
li.push_front(i);
cout << "The initial sequence of integers is : ";
li.showList();
slist<int>::iterator beg = li.begin();
beg += 4;//从首位置向后移四位
slist<int>::iterator it=li.insert(beg,100);//插入100,返回插入节点所在位置的迭代器
cout <<"The insert number is : "<< *it << endl;
cout << "After insert the integer 100, the sequence of integers is :";
li.showList();
slist<int>::iterator cur = li.erase(beg);
//cout << *cur << endl;
cout << "After erase the iterator beg, the sequence of integers is :";
li.showList();
system("pause");
}
测试结果如下:
测试的结果是正确的!
通过实现slist的简单实现,让自己对迭代器有了深入的理解,其实说的明白一点迭代器就是一个被封装的节点指针,通过给它赋值,自增等运算后可以指向任何位置的节点。废话不多说了,《STL源码解析》里自己还有很多东西需要啃,加油!