2022-08-11 算法学习——手打循环双链表

首先是正常使用stl进行链表的使用

双向链表无非是每个节点存储了上一个节点的指针和下一个节点
的指针,可以进行增删等操作,主要这样是O(1)复杂度

//手打链表
#include<iostream>
using namespace std;
const int MAXN= 100010;
struct Node{
    int Nextpos;
    int Frontpos;
};

bool vis[MAXN];

struct List{
    Node Queue[MAXN];

    inline void init(){
        Queue[0].Nextpos=1;
        Queue[1].Frontpos=0;
        Queue[1].Nextpos=0;
    }
    void LeftInsert(int Index,int Pos){
        int LeftIndex=Queue[Pos].Frontpos;
        Queue[LeftIndex].Nextpos=Index;
        Queue[Index].Frontpos=LeftIndex;
        Queue[Pos].Frontpos=Index;
        Queue[Index].Nextpos=Pos;
    }

    void RightInsert(int Index,int Pos){
        int RightIndex=Queue[Pos].Nextpos;
        Queue[Index].Nextpos=RightIndex;
        Queue[RightIndex].Frontpos=Index;
        Queue[Index].Frontpos=Pos;
        Queue[Pos].Nextpos=Index;
    }

    void Remove(int Pos){
        int RightIndex=Queue[Pos].Nextpos;
        int LeftIndex=Queue[Pos].Frontpos;
        Queue[RightIndex].Frontpos=LeftIndex;
        Queue[LeftIndex].Nextpos=RightIndex;
    }
    void print(){
        int Pos=0;
        while(Queue[Pos].Nextpos!=0){
            cout<<Queue[Pos].Nextpos<<" ";
            Pos=Queue[Pos].Nextpos;
        }
        puts("");


    }

}list;


int main(){
    int n;
    cin>>n;
    list.init();
    for (int i=2;i<=n;i++){
        int k,p;
        cin>>k>>p;
        if(p) list.RightInsert(i,k);
        else list.LeftInsert(i,k);
    }
    int m;
    cin>>m;
    for(int i=1;i<=m;i++){
        int Number;
        cin>>Number;
        if(!vis[Number]) list.Remove(Number);
        vis[Number]=1;

     }
    list.print();

    return 0;
}
// 链表的封装以及声明,输出

list stl 的使用

#include<bits/stdc++.h>
using namespace std;
int n,m;
list < int > List;

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        List.push_back(i);
    }
    list < int > ::iterator it,now;
    it = List.begin();
//    cout<<*++++List.end()<<"oo"<<endl;
    int cnt = 0;
    while(!List.empty()) {
        cnt++;
        if(it == List.end()) it = List.begin();
        now = it;
//        cout<<"xx"<<*it<<endl;
        it++;
        if(cnt == m) {
            cnt = 0;
            cout << *now <<' ';
            List.erase(now);
        }
        // it++; 在删除之后移动这个指针是错的,因为这个空间已经没有了,所以指针失效了(暂时这么理解)
    }
    return 0;
}


实际场景中,如何需要对序列进行大量添加或删除元素的操作,而直接访问元素的需求却很少,这种情况建议##使用 list 容器存储序列。

迭代器数组的应用,当需要根据节点信息插入和查找时候使用会很方便

但是比如根据链表头部和尾部的指针来插入和查找就没必要了

但是可以用迭代器指针数组来解决只能迭代查询、插入的问题

修改前代码

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

list < int > List;
int vis[100010];

int main () {
    List.push_back(1);
    list < int > ::iterator it;
    it = List.begin();
    int n;
    scanf("%d",&n);
    for(int i=2;i<=n;i++) {
        int k,p;
        scanf("%d%d",&k,&p);
        for(int j=1;j<i;j++) {
            if(*it == k) break;     // 在k位置插入i这个节点,这里需要先找到节点信息为k的的迭代器,所以解决方法是在每次插入的时候就有一个迭代器数组,存储节点信息为i时的迭代器指针
            ++it;
//            cout << *it << endl;
        }
        if(p == 0) {
            List.insert(it,i);
        }
        else {
            List.insert(++it,i);
        }
        it = List.begin();

    }
    int m;
    scanf("%d",&m);
    while(m--) {
        int x;
        scanf("%d",&x);
        if(!vis[x]) {
            vis[x] = 1;
            for(int i=1;i<=n;i++) {
                if(*it == x) break;  // 每次想要删除节点信息为x的节点时,需要遍历list找到节点信息为x的迭代器指针,再进行删除操作,解决方案有两个,一个时List.erase(pos[x]) //  其中pos[x] 是节点信息为x的迭代器指针,另外一种是List.remove(x),删除节点信息为x的节点
                it++;
            }
            List.erase(it);
            it = List.begin();
        }
    }
    for(;it != List.end();it++) {
        printf("%d ",*it);
    }
    return 0;
}

改进后代码

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

list < int > List;
int vis[100010];

int main () {
    List.push_back(1);
    list < int > ::iterator it[100010];
    it[1] = List.begin();
    int n;
    scanf("%d",&n);
    for(int i=2;i<=n;i++) {
        int k,p;
        scanf("%d%d",&k,&p);
        if(p == 0) {
            it[i] = List.insert(it[k],i);
        }
        else {
            auto nextIt = next(it[k]);
            it[i] = List.insert(nextIt,i);
        }
    }
    int m;
    scanf("%d",&m);
    while(m--) {
        int x;
        scanf("%d",&x);
        if(!vis[x]) {
            vis[x] = 1;
            List.erase(it[x]);  // 注意这里不能用remove,否则超限
        }
    }
    for(auto x : List) {
        printf("%d ",x);
    }
    return 0;
}

posted @ 2024-02-28 21:25  lovevivi121  阅读(8)  评论(0)    收藏  举报  来源