第3章 表、栈和队列

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lc250123/article/details/81633595

目录

表 ADT

STL 库中的向量和链表

iterator 类和 const_iterator 类

向量 ADT 的实现

链表 ADT 实现

栈 ADT

队列 ADT


表 ADT

STL 库中的向量和链表

表 ADT(abstract data type)在 STL 中有两个流行的实现。

vector 给出了表 ADT 的可增长的数组实现。使用 vector 的优点在于其在常量的时间里是可索引的。缺点是插入新项或删除已有项的代价是昂贵的(导致所有元素后移或前移),除非这些操作发生在末尾。

list 提供了表 ADT 的双向链表实现。优点是如果变化发生的位置已知的话,插入新项和删除已有项的代价是很小的。缺点是不容易索引。

vector 和 list 的查找效率都是很低的。


iterator 类和 const_iterator 类

在 STL 中通过内置类型 iterator 来给出一些 ADT 中元素的位置。如:list<int>::iterator、vector<int>::iterator 等。

STL 的 ADT 的实现中不仅包含嵌套的 iterator 类型,也包含嵌套的 const_iterator 类型。iterator 和 const_iterator 的主要区别是:const_iterator 的 operator* 返回常量引用,这样 const_ierator 的 *itr 就不能出现在赋值语句的左边。itertor 的 *itr 可以被修改。

下面是 begin()、end() 的实现,都会有两个来对应使用:

  • iterator begin()
  • const_iterator begin() const
  • iterator end()
  • const_iterator end() const

向量 ADT 的实现

template <typename Object>
class Vector
{
  public:
    explicit Vector( int initSize = 0 )
      : theSize( initSize ), theCapacity( initSize + SPARE_CAPACITY )
      { objects = new Object[ theCapacity ]; }
    Vector( const Vector & rhs ) : objects( NULL )
      { operator=( rhs ); }
    ~Vector( )
      { delete [ ] objects; }

    const Vector & operator= ( const Vector & rhs )
    {
        if( this != &rhs )
        {
            delete [ ] objects;
            theSize = rhs.size( );
            theCapacity = rhs.theCapacity;

            objects = new Object[ capacity( ) ];
            for( int k = 0; k < size( ); k++ )
                objects[ k ] = rhs.objects[ k ];
        }
        return *this;
    }

    void resize( int newSize )
    {
        if( newSize > theCapacity )
            reserve( newSize * 2 + 1 );
        theSize = newSize;
    }

    void reserve( int newCapacity )
    {
        if( newCapacity < theSize )
            return;

        Object *oldArray = objects;

        objects = new Object[ newCapacity ];
        for( int k = 0; k < theSize; k++ )
            objects[ k ] = oldArray[ k ];

        theCapacity = newCapacity;

        delete [ ] oldArray;
    }

    Object & operator[]( int index )
      { return objects[ index ]; }
    const Object & operator[]( int index ) const
      { return objects[ index ]; }

    bool empty( ) const
      { return size( ) == 0; }
    int size( ) const
      { return theSize; }
    int capacity( ) const
      { return theCapacity; }

    void push_back( const Object & x )
    {
        if( theSize == theCapacity )
            reserve( 2 * theCapacity + 1 );
        objects[ theSize++ ] = x;
    }

    void pop_back( )
      { theSize--; }

    const Object & back ( ) const
      { return objects[ theSize - 1 ]; }

    typedef Object * iterator;
    typedef const Object * const_iterator;

    iterator begin( )
      { return &objects[ 0 ]; }
    const_iterator begin( ) const
      { return &objects[ 0 ]; }
    iterator end( )
      { return &objects[ size( ) ]; }
    const_iterator end( ) const
      { return &objects[ size( ) ]; }

    enum { SPARE_CAPACITY = 16 };

  private:
    int theSize;
    int theCapacity;
    Object * objects;
};

链表 ADT 实现

本文讲的是双向链表,一般最好在链表上加上 表头结点 和 尾结点,好处是可以去掉很多特例,可以极大地简化代码。

#ifndef LIST_H
#define LIST_H

template <typename Object>
class List
{
private:
    struct Node
    {
        Object  data;
        Node   *prev;
        Node   *next;

        Node( const Object & d = Object( ), Node *p = NULL, Node *n = NULL )
          : data( d ), prev( p ), next( n ) { }
    };

public:
    class const_iterator
    {
        public:
            const_iterator( ) : current( NULL )
                { }

            const Object & operator* ( ) const
                { return retrieve( ); }

            // 前缀 ++ 用法 ++itr
            const_iterator & operator++ ( )
            {
                current = current->next;
                return *this;
            }
            // 后缀 ++ 用法 itr++,提供一个占位参数以示区分
            const_iterator operator++ ( int )
            {
                const_iterator old = *this;
                ++( *this );    // 等同于调用 ++itr;
                return old;
            }

            bool operator== ( const const_iterator & rhs ) const
                { return current == rhs.current; }
            bool operator!= ( const const_iterator & rhs ) const
                { return !( *this == rhs ); }

        protected:
            Node *current;

            Object & retrieve( ) const
                { return current->data; }

            const_iterator( Node *p ) : current( p )
                { }

        friend class List<Object>;
    };

    /*
     * 在模板继承出现的时候,需要在子类中用this来标志从父类中继承过来的成员函数和变量的调用。
     * 不然用using声明也行。在使用模板继承的时候,如子类中有调用父类的成员函数和变量的情况,
     * 则需要用用this来调用,或者使用using声明,否则会导致在linux的 G++ 上无法编译通过。
     */
    class iterator : public const_iterator
    {
        using const_iterator::current;    // using 声明变量
        using const_iterator::retrieve;    // using 声明函数
        public:
            iterator( )
                { }

            Object & operator* ( )
                { return retrieve( ); }
            const Object & operator* ( ) const
                { return const_iterator::operator*( ); }

            iterator & operator++ ( )
            {
                current = current->next;
                return *this;
            }

            iterator operator++ ( int )    // 此处没有使用 &,因为 *this 改变了,
                                           // old 是使用了复制构造函数新构造了对象
            {
                iterator old = *this;
                ++( *this );
                return old;
            }

        protected:
            iterator( Node *p ) : const_iterator( p )
                { }

        friend class List<Object>;
    };


public:
    List( )
    { init( ); }

    ~List( )
    {
        clear( );
        delete head;
        delete tail;
    }

    List( const List & rhs )
    {
        init( );
        *this = rhs;
    }

    const List & operator= ( const List & rhs )
    {
        if( this == &rhs )
            return *this;
        clear( );
        for( const_iterator itr = rhs.begin( ); itr != rhs.end( ); ++itr )
            push_back( *itr );
        return *this;
    }

    iterator begin()
        { return iterator( head->next); }
    const_iterator begin() const
        { return const_iterator(head->next); }
    iterator end()
        { return iterator(tail); }
    const_iterator end() const
        { return const_iterator(tail); }

    int size() const
        { return theSize; }
    bool empty() const
        { return size() == 0; }

    void clear()
    {
        while (!empty()) {
            pop_front();
        }
    }

    Object & front()
        { return *begin(); }
    const Object & front() const
        { return *begin(); }
    Object & back()
        { return *--end(); }
    const Object & back() const
        { return *--end(); }
    void push_front( const Object & x)
        { insert(begin(), x); }
    void push_back(const Object & x)
        { insert(end(), x); }
    void pop_front()
        { erase(begin()); }
    void pop_back()
        { erase(--end()); }

    // Insert x before itr.
    iterator insert( iterator itr, const Object & x )
    {
        Node *p = itr.current;
        theSize++;
        return iterator( p->prev = p->prev->next = new Node( x, p->prev, p ) );
    }
    // Erase item at itr.
    iterator erase( iterator itr )
    {
        Node *p = itr.current;
        iterator retVal( p->next );
        p->prev->next = p->next;
        p->next->prev = p->prev;
        delete p;
        theSize--;

        return retVal;
    }

    iterator erase( iterator start, iterator end )
    {
        for( iterator itr = start; itr != end; )
            itr = erase( itr );

        return end;
    }

private:
    int theSize;
    Node *head;
    Node *tail;

    void init( )
    {
        theSize = 0;
        head = new Node;
        tail = new Node;
        head->next = tail;
        tail->prev = head;
    }
};

#endif // LIST_H

栈 ADT

栈是限制插入和删除操作只能在一个位置上进行的表,该位置是表的末端,称为栈顶。有时称为 LIFO(后进先出)表。也分两种实现方式:数组实现和链表实现。

栈的打印如下:

template <typename Iterator>
void print( Iterator start, Iterator end, ostream & out = cout )
{
    while( true )
    {
        if( start == end )
            return;

        out << *start++ << endl;   // Print and advance start
    }
}

队列 ADT

队列是在一端插入,一端删除的表。

队列的数组实现:实现方法往往为循环数组实现法。

back 端入队(back + 1),front 端出队(front + 1)。

循环队列空:back ==  front

循环队列满:(back + 1) % MAXSIZE == front

猜你喜欢

转载自blog.csdn.net/lc250123/article/details/81633595