数据结构:链表List的实现与代码分析

跟Vector一样,我自己也写了一个简单的List来进行研究。

这里实现的是双向链表,因为双向链表包含了单向链表的所以功能,所以就没有单独写一个了。

这个双向链表的实现,在创建的时候,就已经有了两个节点,分别是head和tail。这是抽离出来,不存放数据的节点,是为了让程序简化,被称为哨兵节点。

假如不使用哨兵节点,在表头表尾操作的插入删除的时候,有很多要特殊处理的地方。

加了着两个节点,就可以大大简化这些特殊操作。数据上的表头不再试实际代码的表头。

//
//  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__) */
写的过程中,发现还是有好多好多细节要实现的,其实非常繁琐。

估计还有很多很多地方是没有实现的,例如异常检测,还是少了点。

不过可以大致看到原理。

再写个简单的测试程序:

//
//  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;
}



转载于:https://www.cnblogs.com/fablegame/p/6430213.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值