数据结构和标准模板库STL
1.栈 Stack
1.1栈 Stack的定义
- 栈(Stack)是一种特殊的线性表,只能在某一端插入和删除的特殊线性表。它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶。栈也称为先进后出表(LIFO)。
- 允许进行插入和删除操作的一端称为栈顶(Top),另一端为栈底(Bottom)。栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一个元素称为进栈(Push),删除一个栈顶元素称为出栈(Pop)。
1.2容器Stack的使用
stack<int>s;
s.push(1);
s.push(2);
s.push(3);
cout << "Top: " << s.top() << endl;
cout << "Size: " << s.size() << endl;
s.pop();
cout << "Size: " << s.size() << endl;
if(s.empty()) cout << "Is empty" << endl;
else cout << "Is not empty" << endl;
输出:
Top: 3
Size: 3
Size: 2
Is not empty
2.向量Vector
2.1向量Vector的定义
- STL容器Vector是一个动态数组,随机存取任何元素都能在常数时间完成。
- 可以通过迭代器随机的存取,当往其插入新的元素时,如果在结尾插入,将会执行效率比较高,而如果往中间的某个位置插入,其插入位置之后的元素都要后移,因此效率就不是那么的高。
- Vector是一个线性顺序结构,相当于数组,可以不预先指定数组的大小,并且自动扩展。
示例:
int a[10]={12,45,234,64,12,35,63,23,12,55};
char *str="Hello World";
vector <int> vec1(a, a+10); //初值为数组a
vector <char> vec2(str, str+strlen(str)); //初值为字符串str
cout<<"vec1: ";
vector<int> :: iterator p;
for (p=vec1.begin(); p!=vec1.end(); ++p)
cout<<*p<<' ';
cout<<'\n'<<"vec2: ";
vector <char> :: iterator p1;
for (p1=vec2.begin(); p1!=vec2.end();++p1)
cout<<*p1;
输出:
vec1: 12 45 234 64 12 35 63 23 12 55
vec2: Hello World
3.映射Map
- 映射(Map)和多重映射(Multimap)是基于某一类型Key的键集的存在,提供对TYPE类型的数据进行快速和高效的检索。
1.对Map而言,键只是指存储在容器中的某一成员。
2.Multimap允许重复键值,Map不允许。
3.Map和Multimap对象包涵了键和各个键有关的值,键和值的数据类型是不相同的,这与Set不同。 - Map内部数据的组织是一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在Map内部所有的数据Key都是有序的。
示例:
map <string,float,less<string> > c;
c.insert (make_pair("Cafe",7.75));
c.insert (make_pair("Banana",1.72));
c.insert (make_pair("Pizza",30.69));
c["Wine"]=15.66;
map <string,float> :: iterator pos;
for(pos = c.begin(); pos!=c.end(); pos++)
cout<<pos->first<<" "<<pos->second<<endl;
c.clear();
输出:
Banana 1.72
Cafe 7.75
Pizza 30.69
Wine 15.66
4.列表List
- 列表List是一个线性链表结构(Double—Linked Lists,双链表),它的数据由若干个节点构成,每一个节点都包括一个信息块Info(即实际存储的数据)、一个前驱指针Pre和一个后驱指针Post。
- 它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指针将有序的元素链接起来。
示例:
list<int> mylist (8,100); //8个100
mylist.push_back (300); //表尾插入
list<int> :: iterator it = mylist.begin(); //删除元素
mylist.erase(it); //遍历输出
for (it=mylist.begin(); it!=mylist.end(); ++it)
cout << " " << *it;
cout << endl;
输出:
100 100 100 100 100 100 100 300
5.集合Set
- 集合Set是一个容器,它其中所包含的元素的值是唯一的。集合中的元素按一定的顺序排列,并被作为集合中的实例。
- 一个集合通过一个链表来组织,其具体实现采用了红黑树的平衡二叉树的数据结构。
- 在插入操作和删除操作上比向量(Vector)快,但查找或添加末尾的元素时会有些慢。
示例:
set <string> str;
set <string>::iterator pos;
str.insert("apple");
str.insert("orange");
str.insert("banana");
str.insert("grapes");
for (pos=str.begin(); pos!=str.end(); pos++)
cout<<*pos<<" ";
cout<<endl;
str.clear();
输出:
apple banana grapes orange
6.队列Queue
- 队列是一种特殊的线性表,它只允许在表的前端(Front)进行删除操作,而在表的后端(Rear)进行插入操作。
1.进行插入操作的端称为队尾,进行删除操作的端称为队头。
2.队列中没有元素时,称为空队列。 - 在队列这种数据结构中,最先插入在元素将是最先被删除;反之最后插入的元素将最后被删除,因此队列又称为“先进先出”(FIFO—First In First Out)的线性表。
示例:
queue <int> q;
q.push(1); q.push(2); q.push(3); q.push(9);
cout<<q.size()<<endl; //返回队例元素数量
cout<<q.empty()<<endl; //判断队列是否为空
cout<<q.front()<<endl; //读取队首元素
cout<<q.back()<<endl; //读取队尾元素
//所有元素出列,即删除所有元素
while(q.empty()!=true)
{
cout<<q.front()<<" ";
q.pop(); //删除队首元素
}
输出:
4
0
1
9
1 2 3 9
7.优先队列Priority Queue
- 优先队列容器与队列一样,只能从队尾插入元素,从队首删除元素。但是它有一个特性,就是队列中最大的元素总是位于队首,所以出队时,并非按照先进先出的原则进行,而是将当前队列中最大的元素出队。
- 元素的比较规则默认按元素值由大到小排序,可以重载“<”操作符来重新定义比较规则。
示例:
//定义结构体
struct info
{
string name;
float score;
bool operator < (const info &a) const
{
return a.score<score;
}
};
//优先队列
priority_queue <info> pq;
info in;
in.name="Jack"; //学生1
in.score=68.5;
pq.push(in);
in.name="Bomi"; //学生2
in.score=18.5;
pq.push(in);
in.name="Peti"; //学生3
in.score=90;
pq.push(in);
//输出
while(!pq.empty())
{
cout<<pq.top().name
<<": "<<pq.top().score<<endl;
pq.pop();
}
输出:
Bomi: 18.5
Jack: 68.5
Peti: 90
练习习题:
图解:输入:先序遍历 BCDA 中序遍历:CBAD