小白的计蒜客算法笔记——基础数据结构

注:以下内容有任何错误,欢迎指正,谢谢指正

STL库

在C++标准中,STL库被组织为下面的13个头文件:
algorithm算法
deque双重队列
functional函数功能
iterator迭代器
vector向量
list列表
map映射
memory获取对象的实际地址,根据所提供的的对齐和起始地址,返回指向给定大小范围的指针
numeric numeric(5,2)代表总位数为5,小数点后为2的数
queue队列,优先队列
set集合
stack堆栈
utility定义标准模板库类型,函数和运算符,以帮助构建和管理对象,这两个对象视为就可以像在需要时可对。

vector

1.vector实现动态数组
C++中直接构造一个vector的语句为:
vectorfood.
这样就定义了一个名为food,T数据类型的向量,初始为空。
2.**push_back()**在数组最后面插入一个新的元素;pop_back在末尾弹出一个元素。

#include<vector>
using namespace std;
int main(){
vector<int>vec;//[]
vec.push_back(1);//[1]
vec.push_back(2);//[1,2]
vec.pop_back(1);//[2]
return 0;
}

3.C++中通过size()方法获得vector的长度,通过[ ]操作直接访问vector中的元素,这一点和数组是一样的。

#include<vector>
#include<stdio.h>
using namespace std;
int main(){
vector<int>vec;
vec.push_back(1);//[1]
for(int i = 0;i<vec.size();i++){
printf(“%d\n”,vec[i]);
}
return 0;
}

4.

#include<vector>
#include<stdio.h>
using namespace std;
int main(){
vector<int>vec;
vec.push_back(1);//[1]
vec.push_back(2);//[1,2]
vec.push_back(1);//[1,2,1]
vec[1]=3;//[1,3,1]
vec[2]=2;//[1,3,2]
for(int i = 0;i<vec.size();i++){
printf(“%d\n”,vec[i]);
}
return 0;
}

5.clear()清空容器。不会清空内存;
清空内存的方式:
定义一个空的vector x。然后用需要清空的vector和x交换。

  vector<int>v;
    {
    vector<int>x;
    v.swap(x);
    }

set

1.集合set支持高效的插入,删除,和查询,这3个操作的时间复杂度都是O(lgn),n是集合中元素的个数。
数组:插入的时间复杂度是O(1),但是删除和查询都是O(n).
2.C++中用insert()方法向集合中插入一个新的元素。如果集合已经存在某个元素,再次插入不会产生任何效果。
3.C++中通过erase()方法删除集合中的一个元素,如果集合中不存在这个元素,不进行任何操作。
4.C++中如果你想知道某个元素是否在集合中出现,你可以直接用count()方法。如果集合中存在这个元素,就返回1.否则返回0;

#include <set>
#include <string>
#include <stdio.h>
using namespace std;
int main() {
    set<string> country;  // {}
    country.insert("China"); // {"China"}
    country.insert("America"); // {"China", "America"}
    country.insert("France"); // {"China", "America", "France"}
    if (country.count("China")) {
        printf("China belong to country");
    }
    return 0;
}

5.C++通过迭代器可以访问集合中的每个元素,迭代器就好比指向集合中元素的指针。

#include <set>
#include <string>
#include <iostream>
using namespace std;
int main() {
    set<string> country;  // {}
    country.insert("China"); // {"China"}
    country.insert("America"); // {"China", "America"}
    country.insert("France"); // {"China", "America", "France"}
  for(set<string>::iterator it = country.begin();it !=country.end();it++){
cout<<(*it)<<endl;
}
    return 0;
}

6.同样用clear()清空集合。
7.控制集合中最后一个元素没有空格的办法:

for(i=0,it = AUB.begin();it!=AUB.end();it++,i++){
    cout<< * it;
    if(i!=AUB.size()-1) cout<<" ";
}

map

1.映射 map 是指两个集合之间的元素的相互对应关系。比如有一个姓名的集合{“TOM”,”JONE”,”MARY”},班级集合{1,2}。姓名与班级之间可以有如下的映射关系:
class(“TOM”)=1, class(“JONE”)=2, class(“MARY”)=1.
姓名集合为关键字集合(key),班级集合为值集合(value)。
2.
map<T1,T2> m;这样我们定义了一个名为m的从T1数据类型到T2数据类型的映射。
3.在C++中向映射中加入新映射对的时候通过pair(元组)来实现。
如果插入的key之前已经有了value,不会用插入的新的value替代原来的value,插入无效。

#include <map>
#include <string>
using namespace std;
int main() {
    map<string, int> dict;  // {}
    dict.insert(pair<string, int>("Tom", 1)); // {"Tom"->1}
    dict.insert(pair<string, int>("Jone", 2)); // {"Tom"->1, "Jone"->2}
    dict.insert(pair<string, int>("Mary", 1)); // {"Tom"->1, "Jone"->2, "Mary"->1}
    dict.insert(pair<string, int>("Tom", 2)); // {"Tom"->1, "Jone"->2, "Mary"->1}
    return 0;
}

4.dict[“Tom”],就可以获取“Tom”的班级了。

printf(“Mary is in class %d\n”,dict[“Mary”]);

5.如果没有对“Tom”做过映射的话,此时访问dict[“Tom”],系统将会自动生成一个映射,其值为默认值。并且可以赋予新的值。dict[“Tom”]=3;
6.有时我们不希望被自动映射。我们就要知道某个关键字是否被映射过。可以用count()方法。

if(dict.count(“Mary”)){
printf(“Mary is in class %d\n”,dict[“Mary”]);}
else{
printf(“Mary has no class”);
}

7.C++中通过迭代器访问每队映射。每个迭代器的first值对应key,second值对应value

for(map<string,int>::iterator it = dict.begin();it!=dict.end();it++){
cout<<it->first<<”is in class”<<it->second<<endl;
}

映射表

stack

1.栈(stack),又名堆栈,是一种运算受限制的线性表类型的数据结构。其限制是只允许在栈的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。
栈的一个重要性质,先进后出(FILO——first in last out).

#include <stack>
#include <iostream>
using namespace std;
stack<int> S;
int main() {
    S.push(1);
    S.push(10);
    S.push(7);
    while(!S.empty()){
      cout <<S.top()<<endl;  
        S.pop();
    }
    return 0;
}

2.栈的数组手动实现。

int stack[maxsize], top = 0;
void push(int x) {
    stack[top++] = x;
}
void pop() {
   --top;
}
int topval() {
    return stack[top - 1];
}
int empty() {
    return top > 0;
}

queue

1.队列是一种线性的数据结构。
前端队首 front 后端队尾 rear 先进先出 First in first out.
就跟排队一样的。
队列
2.循环队列。在实际使用队列中,为了使队列的空间能够重复使用,一旦队列的头或者尾超出了所分配的队列空间,则让它指向队列的起始位置
类似于百米跑步练习的时候,你是队首,你先跑,然后跑完之后回到队伍的最后面,一直这样循环。
3.在医院里,重症急诊患者肯定不能像普通患者那样排队就诊。这时候我们就需要一种新的数据结构——优先队列。先访问优先级高的元素。(整型中默认数字大的优先级高)
priority_queue

#include<queue>
#include<iostream>
using namespace std;
int main(){
priority_queue<int>q;
q.push(1);
q.push(5);
q.push(3);
while(!q.empty()){
 cout<<q.top()<<endl;
q.pop();
}
return 0;
}
/*
输出为
5
3
1
*/

4.优先队列支持查询优先级最高的元素这一操作,而优先级的高低可以自行定义。
在C++中通过重载小于运算符bool operator<来实现。
5.下面的例子,在算法竞赛中经常出现,这里定义距离值较小的node优先级较高。

struct node{
int dist,loc;
node(){}
bool operator <(const node&a)const {
return dist>a.dist;
}
};
priority_queue <node>Q;

并查集

并查集是一种树型的数据结构,用于处理一些不相加集合的合并查询问题。在使用中常常以森林来表示。
并查集也是用来维护集合的,和前面学习的set不同之处在于,并查集能很方便地同时维护很多集合。如果用set来维护会非常的麻烦。
并查集的核心思想是记录每个结点的父亲节点是哪个结点。
1)初始化:初始的时候每个结点各自为一个集合,
father[i]表示结点i的父亲结点,如果father[i] = i,我们认为这个结点是当前集合根结点。

void init(){
 for(int i = 1;i<=n;i++){
father[i] = i;
}

2)查找:查找结点所在集合的根结点(结点x的根结点也必然是其父亲结点的根结点)

int get(int x){
if(father[x] == x){//x结点就是根结点
    return x;
}
return get(father[x]);//返回父亲结点的根结点
}

3)合并:将两个元素所在的集合合并在一起,通常来说,合并之前先判断两个元素是否属于同一集合。

void merge(int x,int y){
x = get(x);
y = get(y);
if(x!=y){//不在同一个集合
 father[y] = x;
}
}

路径压缩
前面的并查集的复杂度实际上在有些极端情况会很慢。比如树的结构正好是一条链,那么最坏情况下,每次查询的复杂度达到了O(n)。
路径压缩的思想是,我们只关心每个结点的父结点,而并不太关心树的真正结构。这样我们在一次查询的时候,可以把查询路径上的所有结点的father[i]都赋值成为根结点。

int get(int x){
if(father[x] = x){//x结点就是根结点
return x;
}
return father[x] = get(father[x]);//返回父亲结点的根结点,并令当前结点父结点直接为根结点。
}

并查集
带权并查集
是指结点存有权值信息的并查集。并查集以森林的形式存在,而结点的权值,大多是记录该结点与祖先关系的信息。比如权值可以记录该结点到根结点的距离。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值