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;
}

浙公网安备 33010602011771号