zoukankan      html  css  js  c++  java
  • 24 单链表的遍历与优化

    原文:https://www.cnblogs.com/wanmeishenghuo/p/9650726.html 参考狄泰软件相关教程

    问题:

    如何遍历单链表中的每一个元素?

    示例:

     在头部插入元素时,时间复杂度是O(n)。 获取元素时,时间复杂度是O(n*n),因为内层定位位置时有一个O(n)复杂度。

    从理论上来说遍历一个单链表,只需要线性的时间就够了。

    设计思路:

    提供一组相关的遍历函数,遍历时使用这些函数来操作:

     

    move函数的i参数为目标位置,step参数为每次移动的节点数。

    end用来判断当前的游标是否到达了单链表的尾部。

    current返回当前游标指向的数据元素。

    next移动游标,移动的次数根据move中的step的值来决定。

    遍历时,这四个函数必须配合使用才能得到最大效率。

     改进LinkList.h文件中的函数:

    #ifndef LINKLIST_H
    #define LINKLIST_H
    
    #include "List.h"
    #include "Exception.h"
    
    namespace DTLib
    {
    
    template < typename T >
    class LinkList : public List<T>
    {
    protected:
        struct Node : public Object
        {
            T value;
            Node* next;
        };
    
        mutable struct : public Object
        {
            char reserved[sizeof(T)];
            Node* next;
        }m_header;
    
        int m_length;
        int m_step;
        Node* m_current;
    
        Node* position(int i) const    //  O(n)
        {
            Node* ret = reinterpret_cast<Node*>(&m_header);
    
            for(int p = 0; p < i; p++)
            {
                ret = ret->next;
            }
    
            return ret;
        }
    public:
        LinkList()
        {
            m_header.next = NULL;
            m_length = 0;
            m_step = 1;
            m_current = NULL;
        }
    
        bool insert(const T& e)
        {
            return insert(m_length, e);
        }
    
        bool insert(int i, const T& e)   // O(n)
        {
            bool ret = ((0 <= i) && (i <= m_length));
    
            if( ret )
            {
                Node* node = new Node();
    
                if( node != NULL )
                {
                    Node* current = position(i);
    
                    node->value = e;
                    node->next = current->next;
                    current->next = node;
    
                    m_length++;
                }
                else
                {
                    THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element...");
                }
            }
    
            return ret;
        }
    
        bool remove(int i)   // O(n)
        {
            bool ret = ((0 <= i) && (i < m_length));
    
            if( ret )
            {
                Node* current = position(i);
    
                Node* toDel = current->next;
    
                current->next = toDel->next;
    
                delete toDel;
    
                m_length--;
            }
    
            return ret;
        }
    
        bool set(int i, const T& e)   //  O(n)
        {
            bool ret = ((0 <= i) && (i < m_length));
    
            if( ret )
            {
                position(i)->next->value = e;
            }
    
            return ret;
        }
    
        T get(int i) const
        {
            T ret;
    
            if( get(i, ret) )
            {
                return ret;
            }
            else
            {
                THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
            }
    
            return ret;
        }
    
        bool get(int i, T& e) const    // O(n)
        {
            bool ret = ((0 <= i) && (i < m_length));
    
            if( ret )
            {
                e = position(i)->next->value;
            }
    
            return ret;
        }
    
        int find(const T& e) const    //  O(n)
        {
            int ret = -1;
            int i = 0;
    
            Node* node = m_header.next;
    
            while( node )
            {
                if( node->value == e )
                {
                    ret = i;
                    break;
                }
                else
                {
                    node = node->next;
                    i++;
                }
            }
    
            return ret;
        }
    
        int length() const   // O(1)
        {
            return m_length;
        }
    
        void clear()    //  O(n)
        {
            while( m_header.next )
            {
                Node* toDel = m_header.next;
    
                m_header.next = toDel->next;
    
                delete toDel;
            }
    
            m_length = 0;
        }
    
        bool move(int i, int step = 1)
        {
            bool ret = (0 <= i) && (i < m_length) && (step > 0);
    
            if( ret )
            {
                m_current = position(i)->next;
                m_step = step;
            }
    
            return ret;
        }
    
        bool end()
        {
            return (m_current == NULL);
        }
    
        T current()
        {
            if( !end() )
            {
                return m_current->value;
            }
            else
            {
                THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
            }
        }
    
        bool next()   //每次移动step步
        {
            int i = 0;
    
            while((i < m_step) && !end())
            {
                m_current = m_current->next;
                i++;
            }
    
            return (i == m_step);
        }
    
        ~LinkList()   //  O(n)
        {
            clear();
        }
    };
    
    }
    
    #endif // LINKLIST_H
    

    第27、28行我们添加了两个成员变量,第185-226行添加了遍历需要的函数。

    测试程序如下:

    #include <iostream>
    #include "LinkList.h"
    
    
    using namespace std;
    using namespace DTLib;
    
    
    int main()
    {
        LinkList<int> list;
    
        for(int i = 0; i<5; i++)
        {
            list.insert(0,i);
        }
    
        //遍历时必须先调用move函数
        for(list.move(0); !list.end(); list.next())
        {
            cout << list.current() << endl;
        }
    
        return 0;
    }
    

    遍历list时必须先调用move函数,指定位置和步进值step,step是给next函数用的,例如:step为5,则每次调用next函数就会向后移动5个元素。

    结果如下:

    这时的遍历操作时间复杂度是O(n)。

    步进值为2时,结果如下:

    单链表内部封装:

    程序改进:

    #ifndef LINKLIST_H
    #define LINKLIST_H
    
    #include "List.h"
    #include "Exception.h"
    
    namespace DTLib
    {
    
    template < typename T >
    class LinkList : public List<T>
    {
    protected:
        struct Node : public Object
        {
            T value;
            Node* next;
        };
    
        mutable struct : public Object
        {
            char reserved[sizeof(T)];
            Node* next;
        }m_header;
    
        int m_length;
        int m_step;
        Node* m_current;
    
        Node* position(int i) const    //  O(n)
        {
            Node* ret = reinterpret_cast<Node*>(&m_header);
    
            for(int p = 0; p < i; p++)
            {
                ret = ret->next;
            }
    
            return ret;
        }
    
        virtual Node* create()
        {
            return new Node();
        }
    
        virtual void destroy(Node* pn)
        {
            delete pn;
        }
    
    public:
        LinkList()
        {
            m_header.next = NULL;
            m_length = 0;
            m_step = 1;
            m_current = NULL;
        }
    
        bool insert(const T& e)
        {
            return insert(m_length, e);
        }
    
        bool insert(int i, const T& e)   // O(n)
        {
            bool ret = ((0 <= i) && (i <= m_length));
    
            if( ret )
            {
                Node* node = create();
    
                if( node != NULL )
                {
                    Node* current = position(i);
    
                    node->value = e;
                    node->next = current->next;
                    current->next = node;
    
                    m_length++;
                }
                else
                {
                    THROW_EXCEPTION(NoEnoughMemoryException, "No memery to insert new element...");
                }
            }
    
            return ret;
        }
    
        bool remove(int i)   // O(n)
        {
            bool ret = ((0 <= i) && (i < m_length));
    
            if( ret )
            {
                Node* current = position(i);
    
                Node* toDel = current->next;
    
                current->next = toDel->next;
    
                destroy(toDel);
    
                m_length--;
            }
    
            return ret;
        }
    
        bool set(int i, const T& e)   //  O(n)
        {
            bool ret = ((0 <= i) && (i < m_length));
    
            if( ret )
            {
                position(i)->next->value = e;
            }
    
            return ret;
        }
    
        T get(int i) const
        {
            T ret;
    
            if( get(i, ret) )
            {
                return ret;
            }
            else
            {
                THROW_EXCEPTION(IndexOutOfBoundsException, "Invalid parameter i to get element ...");
            }
    
            return ret;
        }
    
        bool get(int i, T& e) const    // O(n)
        {
            bool ret = ((0 <= i) && (i < m_length));
    
            if( ret )
            {
                e = position(i)->next->value;
            }
    
            return ret;
        }
    
        int find(const T& e) const    //  O(n)
        {
            int ret = -1;
            int i = 0;
    
            Node* node = m_header.next;
    
            while( node )
            {
                if( node->value == e )
                {
                    ret = i;
                    break;
                }
                else
                {
                    node = node->next;
                    i++;
                }
            }
    
            return ret;
        }
    
        int length() const   // O(1)
        {
            return m_length;
        }
    
        void clear()    //  O(n)
        {
            while( m_header.next )
            {
                Node* toDel = m_header.next;
    
                m_header.next = toDel->next;
    
                destroy(toDel);
            }
    
            m_length = 0;
        }
    
        bool move(int i, int step = 1)
        {
            bool ret = (0 <= i) && (i < m_length) && (step > 0);
    
            if( ret )
            {
                m_current = position(i)->next;
                m_step = step;
            }
    
            return ret;
        }
    
        bool end()
        {
            return (m_current == NULL);
        }
    
        T current()
        {
            if( !end() )
            {
                return m_current->value;
            }
            else
            {
                THROW_EXCEPTION(InvalidOperationException, "No value at current position ...");
            }
        }
    
        bool next()   //每次移动step步
        {
            int i = 0;
    
            while((i < m_step) && !end())
            {
                m_current = m_current->next;
                i++;
            }
    
            return (i == m_step);
        }
    
        ~LinkList()   //  O(n)
        {
            clear();
        }
    };
    
    }
    
    #endif // LINKLIST_H
    

    调用new生成Node的地方我们全换成了create函数,调用delete销毁Node的地方我们全换成了destroy函数。

    问题:

    封装这两个函数的意义是什么?

    小结:

      

      

      

  • 相关阅读:
    java基础(7)
    log4j日志打印级别动态调整
    前端学习
    windows下 使用vs command tools 和mingw 分别编译 openssl
    收尾作业(3)
    收尾作业(2)
    收尾作业(1)
    收尾作业第一个接口
    图形建模需求
    收尾作业2
  • 原文地址:https://www.cnblogs.com/lh03061238/p/13064045.html
Copyright © 2011-2022 走看看