栈(Stack)和队列(queue)及其应用(C++)

栈操作实例:

栈可试作序列的特例,将栈作为向量的派生类

#include "../Vector/Vector.h"   //以向量为基类,派生出栈模板类
template <typename T> class Stack: public Vector<T> {   //将向量的首/末端作为栈底/顶
public:                         //size(), empty()以及其它开放接口,均可直接沿用
    void push( T const& e ) { insert( size(), e ); }    //入栈
    T pop() { return remove( size()-1 ); }              //出栈
    T& top() { return (*this)[size()-1]; }              //取顶
};

栈的应用

试探回溯法

1.八皇后问题

皇后类

struct Queen {  //皇后类
    int x, y;   //坐标
    Queen (int xx = 0, int yy = 0 ) : x(xx), y(yy) {};
    bool operator==( Queen const& q ) const {   //重载判等操作符,检验不同皇后之间可能存在的冲突
        return (x==q.x)         //行冲突
            || (y==q.y)         //列冲突
            || (x+y == q.x+q.y) //对角线冲突
            || (x-y == q.x-q.y);
    }
    bool operator!=( Queen const& q) const { return !(*this == q); }    //重载不等操作符
};

将存在冲突的皇后判作相等

每行仅能放置一个皇后,先见各皇后分配至每一行。逐个尝试着她们放置到无冲突的某列,若当前皇后在任何列都冲突,则回溯到上一个皇后。

N皇后算法:

void placeQueen ( int N ) {             //N皇后算法:采用试探/回溯的策略,借助栈记录查找结果
    Stack<Queen> solu;          //存放解的栈
    Queen q(0,0);               //原点位置开始
    do {                        //反复试探,回溯
        if ( N <= solu.size() || N <= q.y ) {   //若已出界,则回溯一行,并继续试探下一列
            q = solu.pop(); q.y++; 
        } else {    //试探下一行
            while( ( q.y < N ) && (0 <= solu.find(q) ) )       //通过与已有皇后对比,尝试找到可摆放下一皇后的列
                { q.y++; nCheck++; }
            if ( q.y < N ) {    //存在可摆放的列
                solu.push(q);   //摆上当前皇后
                if ( N <= solu.size() ) nSolu++;     //若部分解已称为全局解,则通过全局变量nSolu计数
                q.x++; q.y==0;                      //转入下一行,从第0列开始,试探下一皇后
            }
        }
    } while( ( 0 < q.x ) || ( q.y < N) );           //所有分支均已或穷举或剪枝之后,算法结束
}

2.迷宫寻径问题

迷宫格点类:

typedef enum { AVAILABLE, ROUTE, BACKTRACKED, WALL } Status;        //迷宫单元状态
//           原始可用的, 当前路径上的, 所有方向尝试失败后回溯的, 不可使用的

typedef enum { UNKNOWN, EAST, SOUTH, WEST, NORTH, NO_WAY } ESWN;    //单元的相对邻接方向

inline ESWN nextESWN (ESWN eswn) { return ESWN( eswn + 1); }        //依次转至下一邻接方向

struct Cell {   //迷宫格点
    int x, y; Status status;
    ESWN incoming, outgoing;    //进入,走出方向
};

#define LABY_MAX 24             //最大迷宫尺寸
Cell laby[LABY_MAX][LABY_MAX];  //迷宫


 

邻格查询:

inline Cell* neighbor (Cell* cell)  {   //查询当前位置的相对格点
    switch ( cell->outgoing ) {
        case EAST : return cell + LABY_MAX ;    //向东
        case SOUTH: return cell + 1        ;    //向南
        case WEST : return cell - LABY_MAX ;    //向西
        case NORTH: return cell - 1        ;    //向北
        default   : exit(-1);  
    }
}

邻格转入:

 inline Cell* advance (Cell* cell)  {       //从当前位置转入相邻格点
    Cell* next;
    switch ( cell->outgoing )   {
        case EAST : next = cell + LABY_MAX; next->incoming = WEST;  break;  //向东
        case SOUTH: next = cell +1;         next->incoming = NORTH; break;  //向南
        case WEST : next = cell - LABY_MAX; next->incoming = EAST;  break;  //向西
        case NORTH: next = cell -1;         next->incoming = SOUTH; break;  //向北
        default : exit(-1);
    }
    return next;
 }

迷宫寻径算法实现

//在格单元s至t之间规划一条道路
bool labyrinth ( Cell Laby[LABY_MAX][LABY_MAX], Cell* s, Cell* t) {
    if ( (AVAILABLE != s->status ) || (AVAILABLE != t->status ) ) return false;     //退化情况
    
    Stack<Cell*> path;     //用栈记录通路
    s->incoming = UNKNOWN;  s->status = ROUTE;  path.push(s);   //起点
    do {    //从起点出发不断试探回溯,直到抵达终点,或者穷尽可能    
        Cell* c = path.top();   
        if ( c == t) return true;       
        while (NO_WAY > (c->outgoing = nextESWN(c->outgoing) ) )        //逐一检查所有方向
            if (AVAILABLE == neighbor(c)->status) break;              //找到尚未试探的方向
        if (NO_WAY <= c->outgoing )     //若所有方向都已尝试
        { c->status = BACKTRACKED; c = path.pop(); }    //向后回溯一步
        else //否则,向前试探一步
            { path.push(c = advance(c) );   c->outgoing = UNKNOWN;  c->status = ROUTE; }
    }while( !path.empty() );
    return false;
} 

------------------------------------------------------------------------------------------------------------------------------------------------------

队列

队列操作实例:

队列按线性的逻辑次序排列,约定新对象只能从一端插入其中,这一端称作队尾;只能总另一端取出已有的元素,这一端称作队头;

元素的插入和删除是修改队列结构的主要两种方式,分别称作入队(enqueue)和出队(dequeue)

队列可视作是序列的特例,故只要将队列作为列表的派生类。

Queue模板类

#include "../List/List.h"   //以List为基类
template <typename T> class Queue: public List<T> { //队列模板类
public:
    void enqueue (T const& e) { insertAsLast(e); }  //入队:尾部插入
    T dequeue() { return remove( first() ); }       //出队:首部删除
    T& front()  { return first()->data; }           //队首
};

 队列应用

1.循环分配器

RoundRobin {    //循环分配器
    Queue Q(clients);       //参与资源分配的所有客户组成队列Q
    while (!ServiceClosed()) {  //在服务关闭之前,反复地
        e = Q.dequeue();    //队首的客户出队
        serve(e);           //并接受服务
        Q.enqueue(e);       //重新入队
    }
}

猜你喜欢

转载自blog.csdn.net/amoscykl/article/details/81331265