2018.11.13---2018.11.18总结

博主本周计划做二分专题,刷洛谷试炼场的线性dp题。在练习中发现之前知识未整合,做dp题浪费时间。还做了简单线性数据结构专题练习,涉及后缀表达式、数据大小尾存放,以及队列安排、表达式括号匹配等,从中获得链式结构软删除的启发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这周想写一个关于二分的专题... 

     忙活忙活下把~.

  2018-11-13 :

     今天做着做这dp题发现其实自己前面的很多知识都没有进行整合,还有有一些部分知识完全忘记了...只保留了某些操作的记忆。直接导致PJ组第三题花了接近六小时时间.其实这个时间是非常不合理的。从一开始就想明白过程,但是却一直想着别人怎么实现,别人怎么想。事实上别人的那篇博客的思路描述是有错误的.直接浪费了两个小时去想一个错误的东西(事后跟博主反馈了,博主那笔也确认这个错误...唯一欣慰的了)

   我需要去阅读书籍和学习新的知识点.但千万别忘记了以前会的。

 

  这周订了个小目标就是把洛谷试炼场上的线性dp刷完。当然二分专题还是要弄的。

在刷线性dp前,做了一组简单线性数据结构的专题练习(很自信的去做最后两道题):

       后缀表达式

      

#include <iostream>
#include <stack>
#include <sstream>
using namespace std;
int main(){

   stack<int> q;
   string s = "";
   int d = 0;
   getline(cin,s);
   int len = s.length();
   for(int i = 0 ; i < len ; i++){
       if( '0'  <= s[i] && s[i] <= '9') d = (d*10 + s[i]-'0');
       else if(s[i] == '.')  q.push(d) ,d = 0 ;
       else if(s[i] == '@') cout << q.top();
       else{
           int num2 = q.top();
           q.pop();
           int num1 = q.top();
           q.pop();
           if(s[i] == '+')  q.push(num1+num2);
           if(s[i] == '-')  q.push(num1-num2);
           if(s[i] == '*')  q.push(num1*num2);
           if(s[i] == '/')  q.push(num1/num2);
       }
   }
}

233都不想吐槽自己....在输入字符串中把数字提取出来.可以利用d = (d*10 + s[i]-'0'); 一个个提取出来...

数字转换字符串也可以阿   s = char(d%10 + '0') + s;

 

@@@@@一开始考虑sscanf() 和sprintf()。。实际上没太认真看...    !!!!!!!!!!!!!(明天翻阅下吧!)

实际上呢..我在查阅资料的时候发现了一个神奇的表达式  if(*((char*)&data) == 0x1)

int big_little_endian(){
    int data = 0x1; 
    if( *((char*)&data) == 0x1)
        return LITTLE_ENDIAN;    // 前面定义的LITTLE_ENDIAN = 0

    return BIG_ENDIAN;    // 前面定义的BIG_ENDIAN = 0
}

计组讲过的...AMD和英特尔的CPU对数据处理的方式不一样..(有待继续研究)

对应数据的高字节存放在低地址就是大尾,反之,高字节存放在高地址的就是小尾。
比如 short int a = 0x1234
大尾存放时:
偏移地址      存放内容
0x0000       0x12
0x0001       0x34

小尾存放:
偏移地址      存放内容
0x0000       0x34
0x0001       0x12

 

  1. int data = 0x1 (一个int占四个字节)
  2. 大尾存放时:
  3. 偏移地址      存放内容
  4. 0x0000           0x00   
  5. 0x0001          0x00
  6. 0x0002          0x00
  7. 0x0003          0x01
  8.  
  9. 小尾存放:
  10. 偏移地址      存放内容
  11. 0x0000           0x01   
  12. 0x0001          0x00
  13. 0x0002          0x00
  14. 0x0003          0x00

 

https://bbs.youkuaiyun.com/topics/220075662  有比较详细的去解释(char*)&data)

有一个回答很是经典

------------------------

            取data的地址
            得到的是一个指针
            然后转换成一个char指针
            也就是说把原来data存放的数据按照char去解释!
            不同的指针类型就是不同的解释方法!

配合代码理解:

#include <cstdio>
#include <iostream>
using std::cout;
 
int main()
{
    int data = 65;
    int *d;
    d = &data;
    char *p;
    //p = &data;//这句编译不通过
    p = (char*)&data;//如1楼所说的
    printf("%d  %d  %d", &data, d, p);
    printf("\n%d %c\n", *d, *p);
    cout << *d << " " << p << "\n";//上下两句输出相同
    return 0;
 
}

 

 

 

队列安排

  

#include <iostream>
#include <cstdio>
using namespace std;

const int mmax = 1e5+5;
int st[mmax][2];  //st[i][0] 代表与i左相邻的结点编号, st[i][1] 代表与i右相邻的结点编号
int main(){

   int n,id,dir,m,d;
   scanf("%d",&n);
   st[0][1] = 1,st[0][0] = -1;
   st[1][0] = 0,st[1][1] = -1;   //-1代表结束
   for(int i = 2; i <= n ;i++){
      scanf("%d%d",&id,&dir);
      int lin = st[id][dir];     //某一个方向的相邻编号
      if(lin == -1){        //
          st[id][dir] = i ;
          st[i][!dir] = id;               //
          st[i][dir] = -1;
      }
      else{
        st[i][dir] = lin,st[i][!dir] = id;
        st[lin][!dir] = i,st[id][dir] = i;
      }
   }
   scanf("%d",&m);
   while(m--){
      scanf("%d",&d);
      if(st[d][0] == -1 && st[d][1] == -1) continue;
      int l = st[d][0] ,r = st[d][1];
      st[l][1] = r;   //d左边的结点指向 d右边的结点
      if(r == -1)  continue;
      st[r][0] = l;
      st[d][0] = -1,st[d][1] = -1;
   }


    int fir = 0;
    while(st[fir][1] != -1){
        cout << st[fir][1] << " ";
        fir = st[fir][1];
    }
}

纯数组模拟了链式的写法。虽然不能释放空间...

这道题最不能忍的就是...我居然忘记了st[fir][0] 和st[fir][1] 是代表fir的两个相邻结点.我以为....跟指针一样 fir++就能得到下一个相邻的结点.....

 

然而PS---->看到了一个树去模拟的思路:

 

#include<cstdio>
struct lol{int lc,rc,v;} d[101000];//v表示是否被删,lc是左儿子(相当于当前点的前面的第一个数),rc是右儿子 (相当于当前点的后面的第一个数)
void dfs(int x)//用中序遍历的方法输出 
{
    if(x==-1)return;//-1代表没空,如果该点为空就不需要再往下找 
    dfs(d[x].lc);//搜左儿子 
    if(d[x].v==0)printf("%d ",x);//搜完左儿子(相当于输完前面的人的编号)输出自己的编号 
    dfs(d[x].rc);//搜右儿子 
}
int main()
{
    int n,m;scanf("%d",&n);
    d[1].v=0;d[1].lc=d[1].rc=-1;
    //-1表示空,初始化第一个点 
    for(int i=2;i<=n;i++)
    {
        int x,y;scanf("%d %d",&x,&y);
        d[i].lc=d[i].rc=-1;d[i].v=0;//先初始化i点 
        if(y==0)
        {
            if(d[x].lc!=0)//当d[x]有左儿子,把当前点的左儿子设为d[x]的左儿子,d[x]左儿子设为当前点
            {d[i].lc=d[x].lc;d[x].lc=i;} 
            //否则,把d[x]有左儿子设为当前点
            else d[x].lc=i;
        }
        else
        {
            if(d[x].rc!=0)//当d[x]有右儿子,把当前点的右儿子设为d[x]的右儿子,d[x]右儿子设为当前点
            {d[i].rc=d[x].rc;d[x].rc=i;} 
            //否则,把d[x]有右儿子设为当前点
            else d[x].rc=i;
        }
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int x;scanf("%d",&x);d[x].v=1;//删除x点 
    }
    dfs(1);//利用中序遍历输出 
}

删除操作:对于每个结点用了一个标记符此元素是否被删除.这种树形结构的删除操作也是非常方便的。

添加元素操作:对于每个结点t它只可能作为根结点rt右儿子或者左儿子.若rt对应的儿子不存在.直接插入即可.

容易犯错的地方... 就是对于每一个新添加的结点必须进行初始化操作.

中序遍历的优势大大体现出来。。。

@@@@@突然给了我一个启发?为什么链式结构的不可以用一个标记符来确定此元素是否被删除?还可以实现快速删除,快速回复.软删除的功能就体现出来了

 

 

表达式括号匹配

#include <iostream>
#include <stack>
using namespace std;

int main(){

     char c;
     bool s = true; //ÓÐЧ
     stack<char> op;
     while(cin >> c){
        if(c == '@') break;
        else if( c == '(' ) op.push(c);
        else if( c == ')' ){
            if(op.size() > 0) op.pop();
            else s = false;
        }
     }
     if( op.size() > 0) s = false;
     if(s)
     cout << "YES" << endl;
     else
     cout << "NO" << endl;

}

括号匹配的核心在于每一个'('的一定要匹配唯一')'的.怎么去实现呢?可以用栈.亦可以用变量去统计当前'('的数量.但是有可能在中途整个表达式就不符合条件了

所以说阿.年轻人还是思路梳理清楚了.一步步写.

PS明天要出题~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值