This slide is based on the book of Mark Allen Weiss
张怀勇等译.
And some materials come from the book : The C++ Standard Library, written by Nicolai M. Josuttis.
表、栈和队列是最简单和最基本的三种数据结构.
每一个有意义的程序都将明晰地至少使用一个这样的数据结构.
而
对于 ADT 这个集合, 可以有像
我们将处理形如
\[A_0,A_1,A_2,\ldots,A_{N-1}\]
的一般的
这个表的大小是
对于除空表之外的表,
由程序者自身来判断函数的功能是否恰当.
对表的所有操作都可以使用数组来实现. 虽然数组是静态分配的, 但是内部存储数组的
数组实现使得
为了避免插入和删除的线性开销, 我们需要允许表可以不连续存储, 否则表的部分甚至全部就需要整体移动.
下图表达了链表的一般思想.
将链表的每一个结点都添加一个指向上一项的链接, 如下图.
这称为
表 ADT 有两个流行的实现:
int size() const //返回容器内的元素个数
void clear() //删除容器中所有的元素
bool empty() //如果容器中没有元素, 则返回 true, 否则返回 false.
事实上, 上面三种方法对所有的
void push_back(const Object & x) |
在表的末尾添加 |
![]() |
![]() |
void pop_back() |
删除表的末尾的对象 | ![]() |
![]() |
const Object & back() const |
返回表的末尾的对象(也提供返回引用的修改函数) | ![]() |
![]() |
const Object & front() const |
返回表的前端的对象(也提供返回引用的修改函数) | ![]() |
![]() |
void push_front(const Object & x) |
在 |
![]() |
|
void pop_front() |
在 |
![]() |
|
Object & operator[](int idx) |
返回 |
![]() |
|
Object & at(int idx) |
返回 |
![]() |
|
int capacity() const |
返回 |
![]() |
|
void reserve(int new Capacity) |
设定 |
![]() |
一些表的操作, 例如在表的中部进行插入和删除的操作, 需要位置标记. 在
在描述某些方法的时候, 为简明起见, 我们使用
iterator begin(): 返回指向容器的第一项的一个适当的迭代器.
iterator end(): 返回指向容器的终止标志(容器中最后一项的后面的位置, 在“边界之外”)的一个适当的迭代器.
for(int i=0;i!=v.size();++i) cout << v[i] << endl;
使用迭代器改写
for(vector<int>::iterator itr=v.begin();itr!=v.end();itr???) cout << itr??? << endl;
在循环终止检测中,
于是上面的代码可以写成
for(vector<int>::iterator itr=v.begin(); itr!=v.end(); ++itr) cout << *itr << endl;
使用操作符重载可以允许迭代器访问当前项, 然后也可以写成
vector<int>::iterator itr=v.begin(); while(itr!=v.end()) cout << *itr++ << endl;//注意 *itr++ 返回结果是 itr 未自增前的地址所存的值.
iterator insert(iterator pos, const Object & x)添加
iterator erase(iterator pos)删除迭代器所给出位置的对象.
iterator erase(iterator start, iterator end)删除所有从位置
c.erase(c.begin(),c.end())
#ifndef REMOVEOTHERITEM_H_INCLUDED
#define REMOVEOTHERITEM_H_INCLUDED
template <typename Container>
void removeEveryOtherItem( Container & lst )
{
typename Container::iterator itr = lst.begin( );
while( itr != lst.end( ) )
{
itr = lst.erase( itr );//注意返回的是调用之前 itr 所指对象的下一个位置.
if( itr != lst.end( ) )
++itr;
}
}
#endif // REMOVEOTHERITEM_H_INCLUDED
// constructing lists
// http://www.cplusplus.com/reference/list/list/list/
#include <iostream>
#include <list>
#include "removeOtherItem.h"
int main ()
{
// constructors used in the same order as described above:
std::list first; // empty list of ints
std::list second (4,100); // four ints with value 100
std::list third (second.begin(),second.end()); // iterating through second
std::list fourth (third); // a copy of third
// the iterator constructor can also be used to construct from arrays:
int myints[] = {16,2,77,29,2,5,10,12,15};
std::list fifth (myints, myints + sizeof(myints) / sizeof(int) );
std::cout << "The contents of fifth are: ";
for (std::list::iterator it = fifth.begin(); it != fifth.end(); it++)
std::cout << *it << ' ';
std::cout << '\n';
removeEveryOtherItem(fifth);
for (std::list::iterator it = fifth.begin(); it != fifth.end(); it++)
std::cout << *it << ' ';
std::cout << '\n';
return 0;
}
假设我们需要将一个集合里的所有项都改为一个特殊的值. 下面的例程工作于
template <typename Container, typename Object>
void change( Container & c, const Object & newValue )
{
typename Container::iterator itr = c.begin( );
while( itr != c.end( ) )
{
*itr++ = newValue;
}
}
当然, 上面的例程在编译上其实没有问题. 为了发现潜在的问题, 假设
考察下面打印整数
void print(const list<int> & lst, ostream & out = cout)
{
list<int>::iterator itr=lst.begin();// 编译器会提示错误.
while(itr != lst.end())
{
out << *itr << endl;
*itr=0; // This is fishy !!! (That means the thing or situation is strange or isn’t as it seems.)
itr++;
}
}
因此,
list<int>::iterator itr=lst.begin();
需要改为
list<int>::const_iterator itr=lst.begin();
其次,
*itr=0;
编译会出错.
编译器还会要求必须使用
两个版本的
使用
template <typename Container>
void printCollection( const Container & c, ostream & out = cout )
{
if( c.empty( ) )
out << "(empty)";
else
{
typename Container::const_iterator itr = c.begin( );
out << "[ " << *itr++; // Print first item
while( itr != c.end( ) )
out << ", " << *itr++;
out << " ]" << endl;
}
}
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;
};
从上面的代码可以看出,
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( ); }
//前置++
const_iterator & operator++ ( )
{
current = current->next;
return *this;
}
//例如 ++itr 调用了零参数 operator++
//后置++
const_iterator operator++ ( int )
{
const_iterator old = *this;
++( *this ); //调用了上面的前置++
return old;
}
//itr++ 调用了单参数 operator++(int), 这里的 int 参数不使用, 其存在的意义仅仅在于给出一个不同的标识, 以区别零参数的 operator++
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 >;
//友元声明(friend declaration), 允许List类访问const_iterator类的非公有成员.
};
class iterator : public const_iterator
{
public:
iterator( )
{ }
Object & operator* ( )
{ return retrieve( ); }
const Object & operator* ( ) const
{ return const_iterator::operator*( ); }
iterator & operator++ ( )
{
current = current->next;
return *this;
}
iterator operator++ ( int )
{
iterator old = *this;
++( *this );
return old;
}
iterator & operator-- ( )
{
current = current->prev;
return *this;
}
iterator operator-- ( int )
{
iterator old = *this;
--( *this );
return old;
}
protected:
iterator( Node *p ) : const_iterator( p )
{ }
//注意这里的初始化列表实际上调用了父类 List::const_iterator 中的构造函数 List::const_iterator::const_iterator(Node * p)
friend class List < Object >;
//友元声明(friend declaration), 允许List类访问iterator类的非公有成员.
};
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;
}
void init( )
{
theSize = 0;
head = new Node;
tail = new Node;
head->next = tail;
tail->prev = head;
}
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 Object x before itr.
iterator insert( iterator itr, const Object & x )
{ /* See Figure 3.18 */
//注意这里可以直接访问itr.current, 是因为 iterator 已经声明其中有友元 List<Object> 了.
Node *p = itr.current;
theSize++; //既然是插入, 当然 theSize 得增加 1.
//注意最后一句
return iterator( p->prev=p->prev->next=new Node(x, p->prev, p) );
}
// Erase item at itr.
iterator erase( iterator itr )
{ /* See Figure 3.20 */
Node *p = itr.current;
iterator retVal( p->next ); //定义了一个名为 retVal 的迭代器, 这里 retVal 是 returnValue 的缩写.
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
theSize--;
return retVal;
}
iterator erase( iterator start, iterator end )
{ /* See Figure 3.20 */
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;
}
};
C++ 需要通过给前缀形式指定空参数表, 给后缀形式指定一个(匿名的)
微软的 FAT 文件系统就采用了链式结构来组织文件块在磁盘上的存放. 不过 FAT 系统效率很低, 早已经被淘汰. 后来微软推出了 NTFS 文件系统. 而 UNIX 的文件系统比较先进, 它将文件以索引结构来组织.
思考一下采用链式结构的 FAT 文件系统为什么效率地下?
例如, 硬币储存罐, 弹匣等.
由于栈是一个表, 因此任何实现表的方法都能实现栈.
使用
在某些机器上, 若在带有自增和自减寻址功能的寄存器上操作, 则对于整数的
大多现代计算机将栈操作作为其指令系统的一部分, 这个事实强化了这样一种思想, 即在计算机科学中, 栈很可能是继数组之后的最基本的数据结构.
#pragma once
#include <vector>
using namespace std;
template <typename Object>
class Stack
{
public:
Stack(int n = 0) : elements(n), top(-1) {};
~Stack() {};
void push(const Object & elementToPush)
{
//elements.length() << 1 是移位运算, 比
//elements.length() * 2 要快
if (++top == elements.size())
{
elements.resize(elements.size() << 1);
}
elements[top] = elementToPush;
}
bool pop(Object & poppedElement)
{
//如果栈是空的
if (top == -1)
return false;
//如果栈非空, 那么位于 top 处的元素就是栈顶元素
poppedElement = elements[top];//按传址方式传递, 见参数传递方式
top--;
//元素已删除, 应该检查是否可以将数组减半, 以节省堆内存. 但是频繁地缩减容量并不能提高效率.
int trysize = elements.size();
while ((top + 1 <= trysize >> 2) && trysize > 2)
trysize >>= 1;
if (trysize < elements.size())
{
//try
//{
elements.resize(trysize);
//}
//catch(e){}
}
return true;
}
// returns the element at the top of the stack
bool peek(Object & topElement)
{
if (top == -1)
return false;
topElement = elements[top];
return true;
}
//也可以按自己的想法命名, 比如 isEmpty()
bool empty() const
{
return top == -1;
}
void makeEmpty()
{
top = -1;
//使用 resize() 释放更多动态内存
//但有可能我们正处于使用完所有堆内存的边缘上, 此时 resize() 函数
//无法创建一个拥有两个元素的新数组. 所以使用 try...catch
try
{
elements.resize(2);
}
catch (bad_alloc e)
{
//bad_alloc
//当使用动态内存分配操作符new时, 如果得不到内存空间的分配, 就抛出类型为 bad_alloc 的异常
//bad_alloc 是一种从基类 exception 派生的类型.
}
}
typedef Object * iterator;
typedef const Object * const_iterator;
iterator begin()
{
if (top == -1)
{
return nullptr;
}
else
{
return &elements[0];
}
}
//注意, end()方法返回的是栈中最后一个元素下一个位置. 因此是top+1这个位置.
iterator end()
{
return &elements[top+1];
//return &elements[elements.size()];
}
const_iterator begin() const
{
if (top == -1)
{
return nullptr;
}
else
{
return &elements[0];
}
}
//注意, end()方法返回的是栈中最后一个元素下一个位置. 因此是top+1这个位置.
const_iterator end() const
{
return &elements[top+1];
//return &elements[elements.size()];
}
//返回栈中元素的个数
int size() const
{
return top+1;
}
private:
vector<Object> elements;
int top;
};
编译器检查程序的语法错误, 但是常常由于缺少一个符号(如遗漏一个花括号或是注释起始符)导致编译器列出上百行的错误, 而真正的错误却并没有找出.
在这个情况下, 一个有用的工具就是一个检验是否所有的东西都成对出现的程序.
为简单起见, 我们仅就圆括号、方括号和花括号进行检验并忽略出现的任何其他字符.
一个简单的算法是用栈. 叙述如下:
可以确信, 这个算法是线性的, 并且事实上它只需对输入进行一次检验. 因此, 是联机(online)的并且相当快.
可以做一些附加的工作来决定当检测出错时如何处理——例如判断可能的原因.
在你的计算器(如便携计算器, 手机应用软件)中输入下面的式子
4.99+5.99+6.99*1.06=
查看结果是
再试一下
4.99*1.06+5.99+6.99*1.06=
可以将这种操作顺序写为:
4.99 1.06 * 5.99 + 6.99 1.06 * +
这种记法叫作
计算这个问题最容易的方法是使用栈.
后缀表达式的优点
栈不仅可以用来计算后缀表达式的值, 而且还可以用来将一个标准形式的表达式(或叫作
a + b * c + (d * e + f) * g
a b c * + d e * f + g * +
算法:
#ifndef QUEUE_H
#define QUEUE_H
//使用单向链表实现队列
//这里单向链表的实现特别是迭代器部分参考了之前的List类
//其余也参考了《C++ Primer Plus》中关于 Queue 的代码, 见第6版 P462.
//这里使用了模板类
template <typename Object>
class Queue
{
private:
struct Node
{
Object item;
struct Node * next;
};
enum {Q_SIZE=10};
public:
//create queue with a qs limit
Queue(int qs=Q_SIZE): qsize(qs), front(nullptr), rear(nullptr), items(0)
{
}
//析构函数 dtor
~Queue()
{
clear();
}
//复制构造函数, 调用operator=函数
Queue(const Queue& rhs)
{
*this = rhs;
}
//operator=函数, 深度复制
const Queue& operator=(const Queue& rhs)
{
if (this == &rhs) return *this; // handle self assignment
//assignment operator
clear( );
for( const_iterator itr = rhs.begin( ); itr != rhs.end( ); ++itr )
enqueue( *itr );
return *this;
}
//队列是否为空
bool empty() const
{
return items==0;
}
//队列是否已满
bool isfull() const
{
return items==qsize;
}
//返回队列中的元素个数//int queuecount() const
int size() const
{
return items;
}
void clear()
{
Node * temp;
while(front!=nullptr)
{
temp=front;
front=front->next;
delete temp;
}
}
//入列, add item to end
bool enqueue(const Object & item)
{
if(isfull())
return false;
Node * add=new Node; //create Node
//on failure, new throws std::bad_alloc exception
add->item=item; //set node pointers
add->next=nullptr; //or NULL
items++;
if(front == nullptr)
front=add;
else
rear->next=add;
rear=add;//更新rear
return true;
}
//出列, remove item from front
bool dequeue(Object & item)
{
if(front==nullptr)
return false;
item=front->item;
items--;
Node* temp=front;
front=front->next;
delete temp;
if(items==0)
rear=nullptr;
return true;
}
public:
//实现迭代器
class const_iterator
{
public:
const_iterator( ) : current( nullptr )
{ }
const Object & operator* ( ) const
{ return retrieve( ); }
const_iterator & operator++ ( )
{
current = current->next;
return *this;
}
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:
Node *current;
const Object & retrieve( ) const
{ return current->item; }
const_iterator( Node *p ) : current( p )
{ }
friend class Queue < Object >;
};
class iterator : public const_iterator
{
public:
iterator( )
{ }
Object & operator* ( )
{
return this->current->item;
//这里使用 return this->retrieve(); 编译出错.
}
const Object & operator* ( ) const
{ return const_iterator::operator*( ); }
iterator & operator++ ( )
{
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;
}
protected:
//Node *current;
iterator( Node *p ) : const_iterator( p )
{ }
/**
* iterator 继承自 const_iterator()
* Object & retrieve( ) const
* { return current->data; }
*
*/
friend class Queue < Object >;
};
iterator begin()
{
return iterator( front );
}
const_iterator begin() const
{
return const_iterator( front );
}
iterator end()
{
return iterator( nullptr);
}
const_iterator end() const
{
return const_iterator( nullptr );
}
private:
Node * front;//指向第一个结点的指针, pointer to front of Queue
Node * rear; //指向最后一个结点的指针, pointer to rear of Queue
int items; //current number of items in Queue
const int qsize;//maximum number of items in Queue
};
#endif // QUEUE_H
直接使用数组实现队列并不太好. 因为如果使用数组, 每次在头部删除元素(出队), 都要将其他元素进行移动. 要使得出队后其他元素在数组中不移动, 可以使用循环数组.
| 操作 | 效果 |
|---|---|
| vector<Elem> c; | 生成一个空的向量c, 其中没有任何元素. |
| vector<Elem> c1(c2); | 生成与 c2 同样的一个向量 c1, 所有元素都被复制. |
| vector<Elem> c(n); | 利用元素的默认构造函数生成一个大小(size)为 $n$ 的向量. |
| vector<Elem> c(n,elem); | 生成一个大小为 $n$ 的向量, 其中每个元素的值都是 elem. |
| vector<Elem> c(begin, end); | 生成一个向量c, 以区间[begin, end]作为元素初值. |
| c.~vector<Elem>(); | 销毁向量c中的所有元素, 并释放内存. |
| 操作 | 效果 |
|---|---|
| list<Elem> c; | 生成一个空的链表(list)c, 其中没有任何元素. |
| list<Elem> c1(c2); | 生成与 c2 同样的一个链表 c1, 所有元素都被复制. |
| list<Elem> c(n); | 利用元素的默认构造函数生成一个大小(size)为 $n$ 的链表. |
| list<Elem> c(n,elem); | 生成一个大小为 $n$ 的链表, 其中每个元素的值都是 elem. |
| list<Elem> c(begin, end); | 生成一个链表c, 以区间[begin, end]作为元素初值. |
| c.~list<Elem>(); | 销毁链表c中的所有元素, 并释放内存. |
#include <iostream>
#include <list>
using namespace std;
int main()
{
cout << "使用迭代器遍历 list" << endl;
list<char> coll; // list container for character elements
//append elements from 'a' to 'z'
for(char c='a'; c<='z'; ++c)
{
coll.push_back(c);
}
/* print all elements
* - iterate over all elements
*/
list<char>::const_iterator pos;
for(pos=coll.begin(); pos!=coll.end(); ++pos)
{
cout << *pos << ' ';
}
cout << endl;
return 0;
}
注意, 使用前置式递增
#include<iostream>
#include<fstream>
#include<stack>
#include<cstdlib>
using namespace std;
bool match(string &file);
int main()
{
string filename;
cout << "*************************************" << endl;
cout << "* This program will check whether the symbols" << endl;
cout << "* () [] {} <> are nested correctly. " << endl;
cout << "*************************************" << endl;
cout << "Please enter the file name: ";
getline(cin,filename);
cout << "\nInput file: " << filename << "\n" << endl;
if(match(filename))
{
cout << "****Congratulations!!****\nYour file's symbols are matched." << endl;
}
else
{
cout << "^^^Sorry^^^\nPlease correct your file" << endl;
}
return 0;
}
bool match(string &file)
{
ifstream File;
stack<char> CC;
File.open(file.c_str());
if(!File)
{
cerr << "Error!!\nUnable to find the file!" << endl;
exit(1);
}
char CH;
int symb;
while(File.get(CH))
{
switch(CH)
{
case'(':symb=1;break;
case')':symb=-1;break;
case'[':symb=2;break;
case']':symb=-2;break;
case'{':symb=2;break;
case'}':symb=-2;break;
case'<':symb=2;break;
case'>':symb=-2;break;
default:symb=0;
}
if(symb > 0)
{
CC.push(CH);
cout << "push " << CH << " in stack" << endl;
}else if(symb<0)
{
if(CC.top()==CH+symb)
{
CC.pop();
cout << "pop " << CH << endl;
}
else
CC.push(CH);
}
}
File.close();
if(CC.size()>0)
{
return false;
}
return true;
}
这里将开符号
刚才的代码对整个文档中的开符号
为简单起见, 这里只列出
//改进match()函数, 使之可以记录行数和列数
bool match(string &file)
{
ifstream File;
stack<char> CC;
File.open(file.c_str());
if(!File)
{
cerr<<"Error!!\nUnable to find the file!"<<endl;
exit(1);
}
char CH;
int symb;
int number_of_lines=1;
int number_of_columns=0;
int number_of_characters=0;
while(!File.eof())
{
File.get(CH);
++number_of_characters;
if(CH=='\n')
{
++number_of_lines;
number_of_columns=0;
}else
{
++number_of_columns;
}
switch(CH)
{
case'(':symb=1;break;
case')':symb=-1;break;
case'[':symb=2;break;
case']':symb=-2;break;
case'{':symb=2;break;
case'}':symb=-2;break;
case'<':symb=2;break;
case'>':symb=-2;break;
default:symb=0;
}
if(symb>0)
{
CC.push(CH);
//cout<<"push "<<CH<<" in stack"<<endl;
}else if(symb<0)
{
if(CC.size()>0 && CC.top()==CH+symb)
{//如果栈中有元素, 且top处的元素和CH是匹配的, 则弹出top处的元素.
CC.pop();
//cout<<"pop "<<CH<<endl;
}
else
{
CC.push(CH);
//cout<<"push "<<CH<<" in stack"<<endl;
cout<<"Line: "<<number_of_lines<<" ; Col: "<<number_of_columns<<endl;
cout<<"-------------------"<<endl;
}
}
}
cout<<"Total characters: "<<number_of_characters-number_of_lines<<endl;
if(number_of_characters==0)
{
number_of_lines=0;
number_of_columns=0;
}
cout<<"Total lines: "<<number_of_lines<<endl;
File.close();
if(CC.size()>0)
{
return false;
}
return true;
}