1.6 链表(数组模拟链表)

1、单链表

acwing 826
由于创建结点时new是动态分配空间,超级慢所以笔试的时候用数组来模拟链表
数组连接
第0个点,值 e[0] = 5 指针 ne[0] = 1
第1个点,值 e[1] = 3 指针 ne[1] = 2
第2个点,值 e[2] = 2 指针 ne[2] = 3
第3个点,值 e[3] = 4 指针 ne[3] = -1
此时可以插入的idx= 4
在第2个点后面插入一个值为6的点:e[idx] = 6, ne[idx] = ne[2], ne[2] = idx
可以看到不是按数组的下标顺序排的,是在逻辑上有顺序;
e[ ],ne[ ]数组都是Int类型,head也是int类型,存放的是逻辑代号。 第k个插入的点下标是k,
单链表只能看到后面一个,不能看到前面一个点,所以在o(n)时间复杂度内只能在第k个点后面插入,不能在第k个位置插入。
注意
1、在定义函数时避免关键字 eg. delete(×) remove(√)
2、第k个插入的(1,2,3…,下标是k-1(0,1,2…
3、初始化init head时并不能加int ?因为不允许重复定义

#include <iostream>
using namespace std;
const int N = 100010;

int head, e[N], ne[N], idx;

//初始化
void init(){
    head = -1;
    idx = 0;
}

//插头
void add_to_head(int x){
    e[idx] = x;
    ne[idx] = head;
    head = idx++;
    
}

//在第k个插入的后面插入X
void add(int k , int x){
    e[idx] = x;
    ne[idx] = ne[k];
    ne[k] = idx++;
    
}

//删除第k个后面
void remove(int k){
    
    ne[k] = ne[ne[k]];//不用考虑内存
}

int main(){
    int m, k, x;
    char op;
    cin>>m;
    
    init();
    
    while(m--){
        cin>>op;
        if(op == 'H'){
            cin>>x;
            add_to_head(x);
            cout<<"h";
        }
        else if(op == 'D'){
            cin>>k;
            if(!k) head = ne[head];
            else remove(k-1);
        }
        else{
            cin>>k>>x;
            add(k-1,x);
            
        }
    }
    for(int i = head; i != -1; i = ne[i]) cout<<e[i]<<' ';
    return 0;
}

2、双链表

** Time Limit Exceeded **往往是因为循环截止条件
1、双链表可以用两个虚拟头结点,前面单接链表也可以搞一个虚拟头结点,这样直接用k就不用考虑k-1
2、可以看到k的右边一个,也可以看到K左边一个,所以只用写一个insert
3、在输出时循环的截止条件是i !=右结点即1,起始条件是i = 0结点的右边一个(这里不能用Idx作为截止条件,因为最增删之后,不知道idx是否还在,所以直接在链表中看,虚拟左端点0的右边就是起始条件,右端点1是终止条件)
4、由于输入操作有字符也有字符串,所以定义时应该用string,并且都用双引号==“ ”==。
5、小心第k个插入的数(k=1,2,3…)但是下标idx从2开始,所以是k+1

#include <iostream>

using namespace std;

const int N = 100010;

int m;
int e[N], l[N], r[N], idx;

void pout(){
    for(int i = r[0]; i != 1; i = r[i]){
        cout<<e[i]<<' ';
    }
    cout<<endl;
}

//在结点k的左边插入x
void insert(int k, int x){
    e[idx] = x;
    l[idx] = l[k];
    r[l[k]] = idx;
    r[idx] = k;
    l[k] = idx;
    idx++;
    //pout();
}

//在结点k的右侧插入x,相当于在r[k]的左边插入
//这是双指针的特点,可以找到k左边的数,而单指针就不可以

//删除结点k
void remove(int k ){
    l[r[k]] = l[k];
    r[l[k]] = r[k];
}


int main(){
    cin>>m;
    string op;//错因,这里是字符串不止字符
    // 0是左端点,1是右端点
    //两个虚拟端点
    l[1] = 0;
    r[0] = 1;
    idx = 2;
    
    while(m--){
        cin>>op;
        int k, x;
        if (op == "L"){
            cin>>x;
            insert(r[0],x);
        }
        else if(op == "R"){
            cin>>x;
            insert(1,x);
        }
        else if(op == "D"){
            cin>>k;
            remove(k+1);//第一个插入的idx是2
        }
        else if(op == "IL"){
            cin>>k>>x;
            insert(k+1, x);
        }
        else{
            cin>>k>>x;
            insert(r[k+1],x);
        }
    }
    
    pout();
    return 0;
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值