C++STL手写版
手写STL,卡常专用。
node为变量类型,可以自由定义,以下不再赘述。
1、stack(栈)
开一个数组,和一个top指针,压栈时++,弹栈时--即可。
struct stack{
int tp;node st[N];
node top(){return st[tp];}
void push(node x){st[++tp]=x;}
void pop(){--tp;}
bool empty(){return !tp;}
void size(){return tp;}
void clear(){tp=;}
}s;
2、queue(循环队列)
用两个指针,记录队头和队尾,达到两端时特判即可。
struct queue{
int l,r,cnt;node qu[N];
node front(){return qu[l];}
void ne(int &x){++x;if(x==N) x=;}
void push(node x){ne(r);qu[r]=x;++cnt;}
void pop(){ne(l);--cnt;}
bool empty(){return !cnt;}
void size(){return cnt;}
void clear(){r=cnt=,l=;}
}q;
3、deque(双端队列)
和队列类似。
struct deque{
int l,r,cnt;node qu[N];
void init(){r=cnt=,l=;}
node front(){return qu[l];}
node back(){return qu[r];}
void ne(int &x){++x;if(x==N) x=;}
void la(int &x){--x;if(!x) x=N-;}
void push_front(node x){la(l);qu[l]=x;++cnt;}
void push_back(node x){ne(r);qu[r]=x;++cnt;}
void pop_front(){ne(l);--cnt;}
void pop_back(){la(r);--cnt;}
bool empty(){return !cnt;}
void size(){return cnt;}
void clear(){r=cnt=,l=;}
}q;
4、priority_queue(优先队列)
具有强大的功能,可以删除任意一个元素。
使用时在node内部重载"<"号,删除元素传该元素的id。
%%%remarkable的手写堆是假的,通常情况下删除堆中元素时并不知道它在堆中的下标,而是知道id。
id值可以在node里维护,就对id开一个互逆数组,同时交换即可。
struct priority_queue{
int cnt,p[N];node heap[N];
void up(int x){
while(x>&&heap[x>>]<heap[x]){
swap(p[heap[x>>].id],p[heap[x].id]);
swap(heap[x>>],heap[x]);
x>>=;
}
}
void down(int x){
int y=x<<;
while(y<=cnt){
if(y<cnt&&heap[y]<heap[y|]) y|=;
if(heap[x]<heap[y]){
swap(p[heap[x].id],p[heap[y].id]);
swap(heap[x],heap[y]);
x=y;y=x<<;
}
else break;
}
}
int size(){return cnt;}
bool empty(){return !cnt;}
void push(node x){heap[++cnt]=x;p[x.id]=cnt;up(cnt);}
node top(){return heap[];}
void pop(){
swap(p[heap[].id],p[heap[cnt].id]);
swap(heap[],heap[cnt]);
p[heap[cnt].id]=;cnt--;
if(cnt) down();
}
void remove(int x){
x=p[x];
swap(p[heap[x].id],p[heap[cnt].id]);
swap(heap[x],heap[cnt]);
p[heap[cnt].id]=;cnt--;
if(x<=cnt){up(x);down(x);}
}
void clear(){cnt=;}
}q;
5、bitset(多位二进制数)
ct数组需预处理,表示每个数中1的个数。
struct bitset{
unsigned long long a[N];
const unsigned long long m=;
void clear(){memset(a,,sizeof(a));}
void set(){for(int i=;i<N;i++) a[i]=m+(m<<)+(m<<)+(m<<);}
void reset(){clean();}
void flip(){for(int i=;i<N;i++) a[i]^=(m+(m<<)+(m<<)+(m<<));}
void set(int x,int y){
if(y==) a[x/]|=(unsigned long long)<<(x&);
else if((a[x/]>>(x&))&) a[x/]^=(unsigned long long)<<(x&);
}
void reset(int x){set(x,);}
void flip(int x){
a[x/]^=(unsigned long long)<<(x&);
}
friend bitset operator | (const bitset &x,const bitset &y){
bitset ans;ans.clear();
for(int i=;i<N;i++) ans.a[i]=x.a[i]^y.a[i];
return ans;
}
friend bitset operator & (const bitset &x,const bitset &y){
bitset ans;ans.clear();
for(int i=;i<N;i++) ans.a[i]=x.a[i]^y.a[i];
return ans;
}
friend bitset operator ^ (const bitset &x,const bitset &y){
bitset ans;ans.clear();
for(int i=;i<N;i++) ans.a[i]=x.a[i]^y.a[i];
return ans;
}
friend void operator |= (bitset &x,const bitset &y){
for(int i=;i<N;i++) x.a[i]|=y.a[i];
return ;
}
friend void operator &= (bitset &x,const bitset &y){
for(int i=;i<N;i++) x.a[i]&=y.a[i];
return ;
}
friend void operator ^= (bitset &x,const bitset &y){
for(int i=;i<N;i++) x.a[i]^=y.a[i];
return ;
}
int count(){
int cnt=;
for(int i=;i<N;i++) cnt+=ct[a[i]&m]+ct[(a[i]>>)&m]+ct[(a[i]>>)&m]+ct[(a[i]>>)&m];
return cnt;
}
bool any(){return count();}
bool none(){return !count();}
}b;
6、set/map(红黑树)
#include<iostream>
#include<cstdio>
#define Red true
#define Black false
using namespace std;
const int N=;
int n;
struct node{
int key,si,we,co;
node *f,*ch[];
void fill(int _key,int _co,int _we,node *now){//初始化节点信息
this->key=_key;this->co=_co;
this->si=this->we=_we;
this->f=this->ch[]=this->ch[]=now;
}
void pushup(){//上传更新
this->si=this->ch[]->si+this->ch[]->si+this->we;
}
void pushdown(){//也是上传更新
for(node *now=this;now->si;now=now->f) now->si--;
}
int getpos(int x){//判断向左或向右走
return (this->key==x)?-:(x>this->key);
}
}I;
struct Red_Black_Tree{
int cnt;
node *rt,*nul;//红黑树没有空指针,所有空指针指向nul
node pool[N],*tail,*re[N];//内存池
void init(){//初始化
cnt=;tail=&pool[cnt];nul=tail++;
nul->fill(,Black,,NULL);rt=nul;
}
node *New(int key){//新建节点
node *now=nul;
if(!cnt) now=tail++;
else now=re[--cnt];
now->fill(key,Red,,nul);//新节点为红色
return now;
}
void rotate(node *now,int pos){//旋转操作
node *c=now->ch[pos^];
now->ch[pos^]=c->ch[pos];
if(c->ch[pos]->si) c->ch[pos]->f=now;
c->f=now->f;
if(!now->f->si) rt=c;//旋到根
else now->f->ch[now->f->ch[]!=now]=c;
c->ch[pos]=now;now->f=c;c->si=now->si;
now->pushup();
}
void insert_transfrom(node *now){//插入调整
for(;now->f->co;){//当父亲为红色,不合法,需要调整
node *fa=now->f,*gr=fa->f;
int pos=fa==gr->ch[];node *un=gr->ch[pos];
if(un->co){//叔叔是红色,父亲和叔叔同时染成黑色
fa->co=un->co=Black;
gr->co=Red;now=gr;
}
else if(now==fa->ch[pos]) rotate(now=fa,pos^);//父亲不是根
else{
gr->co=Red;fa->co=Black;rotate(gr,pos);
}
}
rt->co=Black;//根必须是黑色
}
void remove_transfrom(node *now){//删除调节
for(;now!=rt&&!now->co;){
int pos=now==now->f->ch[];
node *fa=now->f,*br=fa->ch[pos];
if(br->co){//调节颜色一致
br->co=Black;fa->co=Red;
rotate(now->f,pos^);
br=fa->ch[pos];
}
else if(!br->ch[]->co&&!br->ch[]->co){//兄弟的两个儿子都是黑色
br->co=Red;now=fa;//兄弟染成红色
}
else{
if(!br->ch[pos]->co){//保持路径上黑色节点数相同
br->ch[pos^]->co=Black;br->co=Red;
rotate(br,pos);br=fa->ch[pos];
}
br->co=fa->co;br->ch[pos]->co=fa->co=Black;
rotate(fa,pos^);break;
}
}
now->co=Black;
}
void insert(int key){//插入节点
node *now=rt,*fa=nul;int pos;
for(;now->si;now=now->ch[pos]){
now->si++;fa=now;
pos=now->getpos(key);
if(pos==-){//找到对应值
now->we++;return;
}
}
now=New(key);//找到位置,插入节点
if(fa->si) fa->ch[key>fa->key]=now;
else rt=now;
now->f=fa;insert_transfrom(now);
}
node *find(node *now,int key){//查找位置
for(;now->si&&now->key!=key;now=now->ch[now->key<key]);
return now;
}
void remove(int key){
node *res=find(rt,key);
if(!res->si) return;//没有找到
if(res->we>){//有多个,只删除一个
res->we--;res->pushdown();return;
}
node *fa=res,*now=nul;
if(res->ch[]->si&&res->ch[]->si){//有两个儿子,找节点替代自己
for(fa=res->ch[];fa->ch[]->si;fa=fa->ch[]);//找后继
}
now=fa->ch[!fa->ch[]->si];now->f=fa->f;
if(!fa->f->si) rt=now;//当前点是根
else fa->f->ch[fa->f->ch[]==fa]=now;
if(res!=fa){
res->key=fa->key;res->we=fa->we;
}
fa->f->pushdown();
for(node *st=fa->f;fa->we>&&st->si&&st!=res;st->si-=fa->we-,st=st->f);
if(!fa->co) remove_transfrom(now);
re[cnt++]=fa;//回收内存
}
int rnk(int key){//查排名
int res,ans=;
for(node *now=rt;now->si;){
res=now->ch[]->si;
if(now->key==key) break;
else if(now->key>key) now=now->ch[];
else{
ans+=res+now->we;now=now->ch[];
}
}
return ans+res+;
}
int kth(int k){//查数
int res;node *now=rt;
for(;now->si;){
res=now->ch[]->si;
if(k<=res) now=now->ch[];
else if(res+<=k&&k<=res+now->we) break;
else{
k-=res+now->we;now=now->ch[];
}
}
return now->key;
}
int pre(int key){//前驱
int res=;
for(node *now=rt;now->si;){
if(now->key<key){
res=now->key;now=now->ch[];
}
else now=now->ch[];
}
return res;
}
int nxt(int key){//后继
int res=;
for(node *now=rt;now->si;){
if(now->key>key){
res=now->key;now=now->ch[];
}
else now=now->ch[];
}
return res;
}
}rbt;
int main()
{
scanf("%d",&n);rbt.init();//初始化
for(int i=;i<=n;i++){
int op,x;scanf("%d%d",&op,&x);
if(op==) rbt.insert(x);
else if(op==) rbt.remove(x);
else if(op==) printf("%d\n",rbt.rnk(x));
else if(op==) printf("%d\n",rbt.kth(x));
else if(op==) printf("%d\n",rbt.pre(x));
else printf("%d\n",rbt.nxt(x));
}
return ;
}
注释版红黑树
C++STL手写版的更多相关文章
- .NET Services Stack笔记之手写版
- 手写Tomcat
学习JavaWeb之后,只知道如何部署项目到Tomcat中,而并不了解其内部如何运行,底层原理为何,因此写下此篇博客初步探究一下.学习之前需要知识铺垫已列出:Tomcat目录结构.HTTP协议.IO. ...
- 用MXnet实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别
用MXnet实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别 http://phunter.farbox.com/post/mxnet-tutorial1 用MXnet实战深度学 ...
- 手写一套迷你版HTTP服务器
本文主要介绍如何通过netty来手写一套简单版的HTTP服务器,同时将关于netty的许多细小知识点进行了串联,用于巩固和提升对于netty框架的掌握程度. 服务器运行效果 服务器支持对静态文件css ...
- 手写队列以及stl中队列的使用
一,手写队列. struct queue { ; ,rear=,a[maxn]; void push(int x) { a[++rear]=x; } void pop() { first++; } i ...
- gcd手写代码及STL中的使用方法
一.手写代码 inline int gcd(int x,int y){ if(y==0) return x; else return(gcd(y,x%y)); } 二.STL中的使用方法 注:在STL ...
- MNIST手写数字分类simple版(03-2)
simple版本nn模型 训练手写数字处理 MNIST_data数据 百度网盘链接:https://pan.baidu.com/s/19lhmrts-vz0-w5wv2A97gg 提取码:cgnx ...
- 闭关修炼180天--手写持久层框架(mybatis简易版)
闭关修炼180天--手写持久层框架(mybatis简易版) 抛砖引玉 首先先看一段传统的JDBC编码的代码实现: //传统的JDBC实现 public static void main(String[ ...
- 手写简易版RPC框架基于Socket
什么是RPC框架? RPC就是远程调用过程,实现各个服务间的通信,像调用本地服务一样. RPC有什么优点? - 提高服务的拓展性,解耦.- 开发人员可以针对模块开发,互不影响.- 提升系统的可维护性及 ...
随机推荐
- Java与C#不同
1.C#方法定义可以有默认参数,而Java则不支持该方式. C#方法定义 public void ShowMessage(string text,string orderId="" ...
- 【Linux开发】【Qt开发】QT 同时支持鼠标和触摸屏
QT 同时支持鼠标和触摸屏 现在 如果我要使用鼠标 导入环境变量 export QWS_MOUSE_PROTO=MouseMan:/dev/input/mice 使用触摸屏,导入环境变量 export ...
- Flask框架 (四)—— 请求上下文源码分析、g对象、第三方插件(flask_session、flask_script、wtforms)、信号
Flask框架 (四)—— 请求上下文源码分析.g对象.第三方插件(flask_session.flask_script.wtforms).信号 目录 请求上下文源码分析.g对象.第三方插件(flas ...
- [Git] 014 远程仓库篇 第一话
0. 前言 在 [Git] 001 初识 Git 与 GitHub 之新建仓库 中,我在 GitHub 上建了一个仓库 "interesting" 这回的任务 把远程的 " ...
- C++代码审查
C++代码审查 1. 目的与要求 寻找结对编程伙伴,并练习结对编程: 对同伴的作品进行代码复审,设计审查表并填写: 评价同伴的代码,介绍同伴的优缺点. 2. 复审代码 小伙伴李宏达的项目代码与博客地址 ...
- CSP-J&S 2019游记
$Day -???$ 和爱国爱党的$LQX$书记打了个赌,谁$TG$分低请另一个京味斋. $Day 0$ 机房同学去聚餐,美其名曰"散伙饭",可能又有几个进队的... 我没有去,因 ...
- [CQOI2012]模拟工厂 题解(搜索+贪心)
[CQOI2012]模拟工厂 题解(搜索+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1327574 链接题目地址:洛谷P3161 BZOJ P26 ...
- htpwdScan — 一个简单的HTTP暴力破解、撞库攻击脚本
李姐姐之前跟我们分享了子域名枚举工具subDomainBrute<subDomainsBrute — 改进渗透测试时暴力枚举子域名的python脚本>,这回带给我们htpwdScan ht ...
- C++泛型程序设计---算法和提升
算法和提升 算法:所谓算法就是一个求解问题的过程或公式,即,通过一个有穷的计算序列生成结果. 函数模板就是普通函数的泛化:它能对多种数据类型执行动作,并且能用以参数方式传递来的各种操作实现要执行的工作 ...
- ECMAScript 6 学习笔记(一)
ECMAScript 6简介 ECMAScript 6.0(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.它的目标,是使得JavaScript语言可以用来编写 ...