代码
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int m;
int e[N], l[N], r[N];
int idx;
//! 初始化
void init()
{
l[1] = 0, r[0] = 1;//* 初始化 第一个点的右边是 1 第二个点的左边是 0
idx = 2;//! idx 此时已经用掉两个点了
}
//* 在第 K 个点右边插入一个 X
void add(int k, int x)
{
e[idx] = x;
l[idx] = k;
r[idx] = r[k]; //todo 这边的 k 不加 1 , 输入的时候 k+1 就好
l[r[k]] = idx;
r[k] = idx;
idx++;
}//! 当然在 K 的左边插入一个数 可以再写一个 , 也可以直接调用我们这个函数,在 k 的左边插入一个 数 等价于在 l[k] 的右边插入一个数 add(l[k],x)
//*删除第 k个 点
void remove(int k)
{
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int main(void)
{
ios::sync_with_stdio(false);
cin >> m;
init();
while(m--)
{
string op;
cin >> op;
int k, x;
if(op=="R")
{
cin >> x;
add(l[1], x); //! 0和 1 只是代表 头和尾 所以 最右边插入 只要在 指向 1的 那个点的右边插入就可以了
}
else if(op=="L")//! 同理 最左边插入就是 在指向 0的数的左边插入就可以了 也就是可以直接在 0的 有右边插入
{
cin >> x;
add(0, x);
}
else if(op=="D")
{
cin >> k;
remove(k + 1);
}
else if(op=="IL")
{
cin >> k >> x;
add(l[k + 1], x);
}
else
{
cin >> k >> x;
add(k + 1, x);
}
}
for(int i = r[0]; i != 1; i = r[i]) cout << e[i] << ' ';
return 0;
}
y总代码是真牛,remove(k+1)这样头结点和尾结点就永远不会被删掉了。
确实
### 简化小技巧。把head初始化为 0,tail初始化为 N - 1,idx初始化为 1,第 k 个插入的数的下标就是 k。
卧槽牛逼(破音——————)
那此时的head = 0, head是指向下一个的指针吗
我看着单链表head = -1; 表示head指向的下一个为空
妙不可言
请问这时的head为什么不能够等于-1呢
y总的模板挺有意思的,单链表里面 head直接就是第一个节点的下标,双链表里面就多了两个哑节点…感觉单链表里面也可以加入头部哑节点,避开在头部插入时的单调操作。
好理解
感觉“单链表里面 head直接就是第一个节点的下标”这个表述有点不准确。
因为单链表模板中head=-1,-1只是一个数,并不代表某一下标,毕竟若-1作为下标访问数组是属于越界的。
而单链表中head会用-1标记,我想是因为并不存在head=-1时会被e[]或ne[]数组访问的情况,所以才能放心让head初始化为-1,并且让-1作为链表结尾
(我想这也就是双链表模板中采用0 1作为哑节点,宁愿让第k个数插入的使用中都得k+1,也不使用-1 0作为哑节点的原因)
为啥remove(k+1)里面是k+1嘞大佬们
理解了大佬
thank u bro,gangster bro,homie bro,u know what i am saying?
m3
我要diss你
迪士尼
ios::sync_with_stdio(false);
这个是什么意思啊?
cin,cout先把要输出的东西存入缓冲区,再输出,导致效率降低,而这段语句可以来打消iostream的输入输出缓存,可以节省许多时间,使效率与scanf与printf相差无几
谢谢大佬,涨知识了。
但是还是有少部分情况 scanf 和 printf 更快一些
超级详细!
这里可以假设最右边地址是1吗,可以的话怎么改啊
你这画图画的。。。就是欠赞!
#提供一种插入右节点时的不同解决方案。思路类似于删除k节点
for(int i = r[0]; i != 1; i = r[i]) cout << e[i] << ‘ ‘;//// idx不是从2开始吗,为啥这里的i又是1开始啦??
最左边的空节点是链表头,这里的i=r[0]指向的是实际插入链表最左边节点的位置,初始化的时候r[0]=1是直接指向了链表尾。只要在最左边进行了插入r[0]指向的是idx了,所以实际上i不是从1开始的 而是从最左边的idx开始
我靠牛逼啊兄弟,想了半天,看到你这我就明白了,但是如果没在最左边插入是不是就要换个写法了,虽然可能没这种情况hh
我自己写得复杂多了,还得更新左右端点,tql,y总。
简明易懂
#include[HTML_REMOVED]
using namespace std;
const int N = 1e5 + 10;
int m;
int e[N],l[N],r[N];
int idx;
void init(){
r[0]=1,l[1]=0;idx=2;
}
void add(int k, int x){
e[idx]=x;
r[k]=idx;
r[idx]=r[k];
l[r[k]]=idx;
l[idx]=k;
idx++;
}
void remove(int k){
l[r[k]]=l[k];
r[l[k]]=r[k];
}
int main(void){ios::sync_with_stdio(false);
cin>>m;
init();
while(m–){
string op;
cin>>op;
int k,x;
if(op==”L”){
cin>>x;
add(0,x);
}else if(op==”R”){
cin>>x;
add(l[1],x);
}else if(op==”D”){
cin>>k;
remove(k + 1);
}else if(op==”IL”){
cin>>k>>x;
add(l[k + 1],x);
}else{
cin>>k>>x;
add(k + 1,x);
}
}for(int i=r[0];i!=1;i=r[i])
cout<<e[i]<<’ ‘;
return 0;
}问一下大佬们,我这个老是 Output Limit Exceeded怎么解决啊
想问一下大佬们,在最右端插入为啥不是(1,x)而是(l[1],x)
1是尾巴,你还能在尾巴后面插吗?在尾巴左边插入,就相当于插到最右端了
可以问下,为什么是k+1吗
ios::sync_with_stdio(false);这句是什么意思
通过将ios::sync_with_stdio(false)设置为false,可以禁用C输入输出流与C标准库的同步,从而提高输入输出的性能。但是,禁用同步后,就不能混合使用C的输入输出流和C标准库的输入输出函数,否则可能会导致错误或未定义的行为
懂了,谢谢啦
y总6bi
查找怎么写
对于头节点左右插入不懂的可以看看我的打卡,那有张图我感觉挺好
你好朋友,请教下,第K个右边插入x 那个函数,应该
是先r[idx] = r[k];然后l[idx] = k;吧?
是的