• 初识 基本数据结构和stl


    基本数据结构

    双向链表

    用数组模拟链表实现

    双向链表初始化

    l[1]=r[1]=0;r[0]=1;
    

    结点1的左边和右边都是1,结点0的右边是1,为什么结点0会存在?因为后续元素有可能插入到结点1的前面

    插入

    将i插入到x的左边
    • x原本的左边为l[x]

    • 调整后的顺序为l[x],i,x

    • 想象l[x]和x有两根线牵着,现在要增加两根线,想清楚,要怎样修改,才能确保三者的练习

    • l[x]是依托x的存在而存在,不如先对与l[x]相关的数据进行修改

    r[l[x]]=i;l[i]=l[x];
    l[x]=i;r[i]=x;
    
    将i插入到x的右边
    • 同理
    l[r[x]]=i;r[i]=r[x];
    r[x]=i;l[i]=x;
    

    删除

    删除位置位x的元素
    • x左边元素为l[x]

    • x右边元素为r[x]

    • 先解决左右两边元素的的问题

      r[l[x]]=r[x];l[r[x]]=l[x];
      

    切换

    从当前元素切换到下一个元素

    x=r[x]

    从当前元素切换到上一个元素

    x=l[x]

    应用——遍历

    cur=0
    do{
       cur=r[cur];
    }while(cur!=0)
    

    其他实现方法数组和指针

    STL--变长数组vector

    定义

    vector<数据类型> 数组名;

    添加数据

    数组名.push_back(数据);

    第i位数据的访问

    v[i];

    数组长度

    • v.size();
    • 注意变长数组的下标也是从0开始的

    清空数组

    v.clear()

    好处

    相对于二维数组不用浪费多余的内存空间

    STL--栈stack

    定义

    stack<数据类型> 变量名

    进栈

    栈名.push(x)

    出栈

    栈名.pop()

    栈长度

    栈名.size()

    判断栈是否为空

    栈名.empty()

    应用——左右括号匹配问题

    • 括号类型:()[]{}

    • 解决思路:左括号进栈,右括号判断

    • 特判:右括号进栈,栈长为0

    • 判断:退群情况:每种右括号都遇到与自己不同类型的两种相应左括号

      ​ 入群情况:除退群情况外

    • 细节:

      • 数字要一次性读完(542)(在读取字符里的while语句再内嵌一个while语句)
      • 边读入边处理

    STL--队列queue

    定义

    queue<数据类型>队列名

    入队

    队列名.push(数据)

    离队

    队列名.pop()

    队头

    队列名.front()

    队列长度

    队列名.size()

    判断队列是否为空

    队列名.empty()

    STL--双端队列deque

    定义

    deque<数据类型> 队列名

    头/尾部进

    队列名.push_front/back(数据);

    头/尾部出

    队列名.pop_front/back()

    头/尾部出的前提

    • 双端队列不为空
    • 不为空的情况
      1. !deque1.empty() 注:为空,返回值为0,取反为1,if才执行
      2. deque1.empty()==0 or deque1.empty()!=1
      3. deque1.empty()==false or deque1,empty()!=true

    应用

    单调队列的构造

    • 原理:将加入的元素与队首或队尾的元素进行比较,再根据预设的单调性决定要加入的位置

    给定一个n个数的数列,从左到右输出每个区间长度为m的数列段的最大数

    • 方法一:一个一个区间段的进行查找,共需(n-m+1)*m次操作,坏处:空间复杂度高

    • 方法二:双指针法

      头指针指向头,尾指针指向尾,先根据第一个区间段确立最大值,坏处:最大值可能有多个(需要多设一个变量来统计最大值个数,比较复杂)

    • 方法三:单调队列, 先根据第一个区间创建一个单调队列,添加元素时比较头尾,长度到达m时开始去头操作

    • 方法四:单调队列,单调队列存位置

      • 加入元素为x,x所对应的值为a[x]
      • 队列长度为x-dq.front()+1大于等·x-dq.front()+1
      • 队列开始去头的条件为x-dq.front()+1>m
      • 由于去头是留到最后的,不妨把最大值的坐标留到第一位,而为了实现这样的操作,在从尾巴入的时候就要入小的,而入小的,换种想法可以把前面大的踢掉(但题目要求的是大的),所以这种想法是错的,所以队列的尾巴应该入大的,把前面小的给踢掉。
    #include<iostream>
    #include<deque>
    using namespace std;
    int main()
    {
    	deque<int> deque1;
    	int n,m;
    	cin>>n>>m;
    	int a[n+1];
    	for(int i=0;i<n;i++)
    	{
    		cin>>a[i];
    		
    		while(!deque1.empty()&&a[deque1.back()]<=a[i])
    		    	deque1.pop_back();
    		deque1.push_back(i);
    		
    		while(deque1.empty()!=1&&i-deque1.front()+1>m)
    		    deque1.pop_front();
    	    //if(i-deque1.front()+1==m)	deque1.front()有可能被更新掉
    		if(i>=m-1) 
    		    cout<<a[deque1.front()]<<" ";	    
    	}
    	return 0;
    }
    

    1714切蛋糕

    • max(sum[i]-sum[j]) (j属于[i-(m-1),i-1])
    • 方法一是
    • sum[i]-min(sum[j])(j属于[i-(m-1),i-1])

    技巧

    • 要求一个含减号的式子的最大值,若被减数是不变的,则原问题可转换为求减数的最小值
    • 若减数随区间移动而变化,可考虑使用单调队列

    • 定义:一种集合
    • 度:一个结点的子结点数
    • 叶结点:没有度的结点
    • 父结点:可以往上爬的结点
    • 子结点:可以往下跑的结点
    • 根结点:没有父节点的结点
    • 兄弟结点:与自己共用父结点的结点

    二叉树

    数组实现方式

    • 当前结点x
    • 左子节点l[x],建立l数组用来存放各个数的左结点
    • 右左节点r[x],建立r数组用来存放各个数的右结点
    • -1表示无该子结点
    • l[l[l[l[l[x]]]]]x的左左左左结点,寻找方法:dfs()或while()

    前序遍历

    void dfs(int x){
         cout<<x;
         if(l[x]!=-1)dfs(l[x]);
         if(r[x]!=-1)dfs(r[x]);
    }
    

    中序遍历

    void dfs(int x){
         if(l[x]!=-1)dfs(l[x]);
         cout<<x;
         if(r[x]!=-1)dfs(r[x]);
    }
    

    应用——已知中序后序求前序

    • 思路:字符串存储,用后序最后一个元素去确认中序的的位置,然后对中序字符串分左右,并把中序的左子树的最右位置用到后序上(中序和后序的左子树部分在内容上(不包括顺序)是重合的)。

    STL--优先队列

    优先队列

      ``priority_queue<``int``,vector<``int``>,greater<``int``> >que3;``//注意“>>”会被认为错误, 
                               ``//这是右移运算符,所以这里用空格号隔开 
    

    模板

    priority_queue<int,vector<int>,greater/less<int> > pqx

    在优先队列与结构体的结合

    在优先队列中使用结构体的若干小结Goozy

    模板

    使用优先队列时,如果需要对Time中的start从小到大排序,有两种方法:

    priority_queue<Time> pq;
    

    一.在结构体外重载结构体小于运算符:

    bool operator <(const Time& a,const Time& b){
     return a.start > b.start;
    }  //这里以大于重载小于是因为默认情况下,优先队列是以大的作为队首,这样一反,就可以再默认情况下使得小的作为队首二.直接在结构体中重载小于运算符:
    

    二.直接在结构体中重载小于运算符:

    struct Time{  
     int start, end;  
     bool operator < (const Time& t)const{  
            return start > t.start;  
        }  //用大于号去重载小于号
       };  
    

    其他

    1e10和128M的关系

    • 1MB=1024KB=1024KB*1024=1048576B=1.048576e6B
    • 1int占4个字节,1e10占4e10的字节

    重载

    • 重新定义

    register int

    register 是表示使用cpu内部寄存器(寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件)的变量,而平时的int是把变量放在内存中,存到寄存器中可以加快变量的读写速度。

    断环为链

    • 二倍长度
    • a[i+n]=a[i]
  • 相关阅读:
    深度学习100问之深度学习的本质
    Docker在Windows下的安装以及Hello World
    杂谈——如何在CSDN上上传图片,并添加到自定义栏目中
    打造livecd的注意事项
    打造livecd的注意事项
    磁盘管理基础
    磁盘管理基础
    磁盘管理基础
    磁盘管理基础
    LFS资料和SSH远程登录全过程
  • 原文地址:https://www.cnblogs.com/BeautifulWater/p/14409737.html
Copyright © 2020-2023  润新知