五、队(Queue)
前一篇讲了栈(Stack),队和栈其实只有一个差别,栈是先进后出,队是先进先出,如图:
从图中可以看出,队有两个常用的方法,Enqueue和Dequeue,顾名思义,就是进队和出队了。队和栈一样,既可以用数组实现,也可以用链表实现,我还是偏向于用数组,我的实现示意图如下:
队有啥用呢?一个最常用的用途就是“buffer”,即缓冲区,比如有一批从网络来的数据,处理需要挺长的时间,而数据抵达的间隔并不均匀,有时快,有时慢,先来的先处理,后来的后处理,于是你创建了一个队,用来缓存这些数据,出队一笔,处理一笔,直到队列为空。当然队的作用远不止于此,下面的例子也是一个很经典的例子,希望读者能举一反三。
例子:使用队对树进行广度优先遍历。
广度优先区别于深度优先,即优先遍历最靠近根节点的各个节点:
我们的算法是:
1,根节点入队
2,出队一个节点,算一次遍历,直到队列为空
3,将刚出队的节点的子节点入队
4,转到2
队列的状况如下图:
树的遍历一般习惯使用递归,理论上所有的递归都可以转变为迭代,如何实现这个转变?队就是其中一种有效的办法,OK,下面我给出上述例题的代码以及注释。
//
Not grace code but enough for demo. ^_^
#include " stdio.h "
// The Node
//
struct Node
{
Node( char cChar, int iSubNodeNum = 0 );
~ Node();
char m_cChar;
int m_iSubNodeNum;
Node ** m_arrNodePointer; // Pointers to the sub-node.
};
Node::Node( char cChar, int iSubNodeNum)
{
m_cChar = cChar;
m_iSubNodeNum = iSubNodeNum;
if (iSubNodeNum != 0 )
m_arrNodePointer = new Node * [iSubNodeNum];
else
m_arrNodePointer = NULL;
}
Node:: ~ Node()
{
if (m_arrNodePointer != NULL)
delete[] m_arrNodePointer;
}
// The Queue
//
class Queue
{
public :
Queue( int iAmount = 10 );
~ Queue();
// return 0 means failed, return 1 means succeeded.
int Enqueue(Node * node);
int Dequeue(Node * & node);
private :
int m_iAmount;
int m_iCount;
Node ** m_ppFixed; // The pointer array to implement the queue.
int m_iHead;
int m_iTail;
};
Queue::Queue( int iAmount)
{
m_iCount = 0 ;
m_iAmount = iAmount;
m_ppFixed = new Node * [iAmount];
m_iHead = 0 ;
m_iTail = iAmount - 1 ;
}
Queue:: ~ Queue()
{
delete[] m_ppFixed;
}
int Queue::Enqueue(Node * node)
{
if (m_iCount < m_iAmount)
{
++ m_iTail;
if (m_iTail > m_iAmount - 1 )
m_iTail = 0 ;
m_ppFixed[m_iTail] = node;
++ m_iCount;
return 1 ;
}
else
return 0 ;
}
int Queue::Dequeue(Node * & node)
{
if (m_iCount > 0 )
{
node = m_ppFixed[m_iHead];
++ m_iHead;
if (m_iHead > m_iAmount - 1 )
m_iHead = 0 ;
-- m_iCount;
return 1 ;
}
else
return 0 ;
}
// Main
//
int main( int argc, char * argv[])
{
// Construct the tree.
Node nA( ' A ' , 3 );
Node nB( ' B ' , 2 );
Node nC( ' C ' );
Node nD( ' D ' , 3 );
Node nE( ' E ' );
Node nF( ' F ' , 2 );
Node nG( ' G ' );
Node nH( ' H ' , 1 );
Node nI( ' I ' );
Node nJ( ' J ' );
Node nK( ' K ' );
Node nL( ' L ' );
nA.m_arrNodePointer[ 0 ] = & nB;
nA.m_arrNodePointer[ 1 ] = & nC;
nA.m_arrNodePointer[ 2 ] = & nD;
nB.m_arrNodePointer[ 0 ] = & nE;
nB.m_arrNodePointer[ 1 ] = & nF;
nD.m_arrNodePointer[ 0 ] = & nG;
nD.m_arrNodePointer[ 1 ] = & nH;
nD.m_arrNodePointer[ 2 ] = & nI;
nF.m_arrNodePointer[ 0 ] = & nJ;
nF.m_arrNodePointer[ 1 ] = & nK;
nH.m_arrNodePointer[ 0 ] = & nL;
Queue que;
que.Enqueue( & nA);
Node * pNode;
while (que.Dequeue(pNode) == 1 )
{
printf( " %c " , pNode -> m_cChar);
int i;
for (i = 0 ; i < pNode -> m_iSubNodeNum; i ++ )
{
que.Enqueue(pNode -> m_arrNodePointer[i]);
}
}
return 0 ;
}
#include " stdio.h "
// The Node
//
struct Node
{
Node( char cChar, int iSubNodeNum = 0 );
~ Node();
char m_cChar;
int m_iSubNodeNum;
Node ** m_arrNodePointer; // Pointers to the sub-node.
};
Node::Node( char cChar, int iSubNodeNum)
{
m_cChar = cChar;
m_iSubNodeNum = iSubNodeNum;
if (iSubNodeNum != 0 )
m_arrNodePointer = new Node * [iSubNodeNum];
else
m_arrNodePointer = NULL;
}
Node:: ~ Node()
{
if (m_arrNodePointer != NULL)
delete[] m_arrNodePointer;
}
// The Queue
//
class Queue
{
public :
Queue( int iAmount = 10 );
~ Queue();
// return 0 means failed, return 1 means succeeded.
int Enqueue(Node * node);
int Dequeue(Node * & node);
private :
int m_iAmount;
int m_iCount;
Node ** m_ppFixed; // The pointer array to implement the queue.
int m_iHead;
int m_iTail;
};
Queue::Queue( int iAmount)
{
m_iCount = 0 ;
m_iAmount = iAmount;
m_ppFixed = new Node * [iAmount];
m_iHead = 0 ;
m_iTail = iAmount - 1 ;
}
Queue:: ~ Queue()
{
delete[] m_ppFixed;
}
int Queue::Enqueue(Node * node)
{
if (m_iCount < m_iAmount)
{
++ m_iTail;
if (m_iTail > m_iAmount - 1 )
m_iTail = 0 ;
m_ppFixed[m_iTail] = node;
++ m_iCount;
return 1 ;
}
else
return 0 ;
}
int Queue::Dequeue(Node * & node)
{
if (m_iCount > 0 )
{
node = m_ppFixed[m_iHead];
++ m_iHead;
if (m_iHead > m_iAmount - 1 )
m_iHead = 0 ;
-- m_iCount;
return 1 ;
}
else
return 0 ;
}
// Main
//
int main( int argc, char * argv[])
{
// Construct the tree.
Node nA( ' A ' , 3 );
Node nB( ' B ' , 2 );
Node nC( ' C ' );
Node nD( ' D ' , 3 );
Node nE( ' E ' );
Node nF( ' F ' , 2 );
Node nG( ' G ' );
Node nH( ' H ' , 1 );
Node nI( ' I ' );
Node nJ( ' J ' );
Node nK( ' K ' );
Node nL( ' L ' );
nA.m_arrNodePointer[ 0 ] = & nB;
nA.m_arrNodePointer[ 1 ] = & nC;
nA.m_arrNodePointer[ 2 ] = & nD;
nB.m_arrNodePointer[ 0 ] = & nE;
nB.m_arrNodePointer[ 1 ] = & nF;
nD.m_arrNodePointer[ 0 ] = & nG;
nD.m_arrNodePointer[ 1 ] = & nH;
nD.m_arrNodePointer[ 2 ] = & nI;
nF.m_arrNodePointer[ 0 ] = & nJ;
nF.m_arrNodePointer[ 1 ] = & nK;
nH.m_arrNodePointer[ 0 ] = & nL;
Queue que;
que.Enqueue( & nA);
Node * pNode;
while (que.Dequeue(pNode) == 1 )
{
printf( " %c " , pNode -> m_cChar);
int i;
for (i = 0 ; i < pNode -> m_iSubNodeNum; i ++ )
{
que.Enqueue(pNode -> m_arrNodePointer[i]);
}
}
return 0 ;
}