【数据结构】链表+栈+队列

目录

链表

单链表 

数组做法

 双链表 

数组做法

stl做法 

题目

 栈

栈的基本操作 

 栈的数组模拟做法

栈的stl做法 

题目

队列

队列 

队列的基本操作 

队列的数组模拟做法

队列的stl做法

题目


链表
单链表 

概念:单向链表是最基本的链表结构,由data数据和next节点组成。data指的是存放的数据,而next则指向下一个节点。链表一般还会有一个head表头head指向链表的第一个节点,因为我们添加完所以节点后链表会指向链表尾部,而使用一般从表头开始使用,所以需要head

单链表的基本操作:

初始化 init      头节点的下标指向-1,目前使用的节点的下标指向头节点下标的下一个     

将x插到头结点 add_to_head      目前节点下标等于头节点下标,头节点指向下一个      

将x插到下标是k的后面add          目前节点下标的下一个指向k,k的下一个指向插入节点       

将下标是k的点后面的点删掉remove      k的后面一个值直接指向k后面的后面一个数

例题:Acwing  826  单链表

实现一个单链表,链表初始为空,支持三种操作:

  1. 向链表头插入一个数;
  2. 删除第 k 个插入的数后面的数;
  3. 在第 k 个插入的数后插入一个数。
数组做法
#include<iostream>
using namespace std;
const int N=1e5+5;

//head 表示头结点的下标 
//e[i] 表示节点i的值 
//ne[i] 表示节点i的next指针是多少,下标 
//idx  存储当前已经用到了哪个点 
int head,e[N],ne[N],idx;

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

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

//将x插到下标是k的后面  
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;
	cin>>m;
	init();
	while(m--){
		int k,x;
		char op;
		cin>>op;
		if(op=='H'){
			cin>>x;
			add_to_head(x);
		}
		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;
}

答疑:

 双链表 

 双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱

双链表的基本操作:

初始化:左端点左边是1,右端点左边是0

在节点k右边插入x:  先让k指针右边的点的左边指向新的点,k指针右边指向新的点(此步k指              针右边的点发生改变)

在节点k的左边插入x:  调用 add[ l[k] , x] ,在k节点的左边一个点的后面插入等价于在k节点的                左边插入

删除第k个点:此节点的右边直接等于左边,左边直接等于右边

 例题 Acwing  827  双链表

实现一个双链表,双链表初始为空,支持 5 种操作:

  1. 在最左侧插入一个数;
  2. 在最右侧插入一个数;
  3. 将第 k 个插入的数删除;
  4. 在第 k 个插入的数左侧插入一个数;
  5. 在第 k 个插入的数右侧插入一个数
数组做法
#include<iostream>
using namespace std;
const int N=1e5+5;

//e[i]  存储当前指针的值 
//l[i]  存储i节点左边的下标
//r[i]  存储i节点右边的下标
//idx   记作当前节点的下标 
int n,m;
int e[N],l[N],r[N],idx;

//初始化 
void init(){
	r[0]=1,l[1]=0;  //0:head   1:tail
} 

//在节点a的右边插入一个数x 
void insert(int a,int x){
	e[idx]=x;
	l[idx]=a,r[idx]=r[a];
	l[r[a]]=idx,r[a]=idx++;
} 

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

int main(){
	cin>>m;
	init(); 
	idx=2;
	while(m--){
		string op;
		cin>>op;
		int k,x;
		if(op=="L"){
			cin>>x;
			insert(0,x);
		}
		else if(op=="R"){
			cin>>x;
			insert(l[1],x);
		}
		else if(op=="D"){
			cin>>k;
			remove(k+1);
		}
		else if(op=="IL"){
			cin>>k>>x;
			insert(l[k+1],x);
		}
		else{
			cin>>k>>x;
			insert(k+1,x);
		}
	}
	for(int i=r[0];i!=1;i=r[i]){
		cout<<e[i]<<' ';
	}
	return 0;
}
stl做法 
#include<bits/stdc++.h>
using namespace std;
 
typedef long long ll;
 
const int N = 2e5+5;
 
int main(){
	int n;
	cin>>n;
	
	list<int> lis;
	unordered_map<int,list<int>::iterator> mp;
	
	int num=0;
	while(n--){
		string op;
		cin>>op;
		if(op=="IL"){
			int k,x;
			cin>>k>>x;
			mp[++num]=lis.insert(mp[k],x);
		}
		else if(op=="IR"){
			int k,x;
			cin>>k>>x;
			auto nxt=next(mp[k]);
			mp[++num]=lis.insert(nxt,x);
		}
		else if(op=="L"){
			int x;
			cin>>x;
			mp[++num]=lis.insert(lis.begin(),x);
		}
		else if(op=="R"){
			int x;
			cin>>x;
			mp[++num]=lis.insert(lis.end(),x);
		}
		else if(op=="D"){
			int k;
			cin>>k;
			lis.erase(mp[k]);
			mp.erase(k);
		}
	}	
	
	for(auto i:lis){
		cout<<i<<' ';
	}
	cout<<"\n";
 
	
	return 0;	
 
}

题目

队列安排 https://www.luogu.com.cn/problem/P1160 

abc 344 E - Insert or Erase  https://atcoder.jp/contests/abc344/tasks/abc344_e

牛客周赛31第4题  https://ac.nowcoder.com/acm/problem/267787

洛谷 单链表  https://www.luogu.com.cn/problem/B3631

 栈

栈:先进后出 ,从队尾进,队尾出,队顶为队尾

栈的基本操作 

数组模拟栈的基本操作

插入                             stk[++tt]=x;

弹出                             tt--; 

判断栈是否为空           if(tt>0) not empty

栈顶                             stk[tt];

stack <int>  st 基本操作

st.push()           插入一个元素

st.top()             取最后一个插入元素

st.pop()            删除最后一个插入元素

st.empty()       判断栈是否为空

 栈的数组模拟做法
//数组模拟做法
#include<iostream>
using namespace std;
const int N=1e5+5;

int m;
int st[N],tt;
 
int main(){
	cin>>m;
	while(m--){
		string op;
		int x;
		cin>>op;
		if(op=="push"){
			cin>>x;
			st[++tt]=x;
		}
		else if(op=="pop"){
			tt--;
		}
		else if(op=="empty"){
			cout<<(tt ? "NO" : "YES")<<endl;
		}
		else cout<<st[tt]<<endl;
	}
	return 0;
}
栈的stl做法 
//stl做法
#include<iostream>
#include<stack>
using namespace std;
stack<int> st;

int main(){
	string op;
	int x;
	int m;
	cin>>m;
	while(m--){
		cin>>op;
		if(op=="push"){
			cin>>x;
			st.push(x);
		}
		else if(op=="pop"){
			st.pop();
		}
		else if(op=="empty"){
			if(st.empty()) cout<<"YES"<<endl;
			else cout<<"NO"<<endl;
		}
		else if(op=="query"){
			cout<<st.top()<<endl;
		}
	}
	return 0;
}

题目

 Acwing  828  模拟栈

队列 

队列:先进先出,从队尾进,队头出,队顶为队头

队列的基本操作 

数组模拟基本操作:

push :入队,从队尾入队

pop : 队头出队,队头下标直接向后移一位

empty: 队尾大于队头即不为空

query:查询队头元素

队列的stl做法:

push:从队尾插入一个元素

pop:从队头出队

empty:判空

query:查询队头元素

队列的数组模拟做法
#include<iostream>
using namespace std;
const int N=1000010;
int n,k;
int a[N],q[N];  //a[i]存储每个值,q[i]存储下标 
int main(){
    cin>>n>>k;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    //求最大值 
    int hh=0,tt=-1;  //保证队头在队尾的右边 
    for(int i=0;i<n;i++){
        if(hh<=tt&&i-k+1>q[hh]) hh++;  //i向前走一步,长度大于k,便减一 
        while(hh<=tt&&a[q[tt]]>=a[i]) tt--;  //队尾与新值比较,新值较大,队尾出队 
        q[++tt]=i;  //队尾下标加一 ,即删除 
        if(i>=k-1) cout<<a[q[hh]]<<' '; //结束的时候,空栈时,队头为窗口的最小值
    }
    puts("");
    
    //求最小值。同理 
    hh=0,tt=-1;
    for(int i=0;i<n;i++){
        if(hh<=tt&&i-k+1>q[hh]) hh++;
        while(hh<=tt&&a[q[tt]]<=a[i]) tt--;
        q[++tt]=i;
        if(i>=k-1) cout<<a[q[hh]]<<' ';
    }
    puts("");
    return 0;
}
队列的stl做法
#include <iostream>
#include <cstring>
#include <algorithm>
#include <deque>
using namespace std;

const int N = 1000010;
int a[N];
int main()
{
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];//读入数据
    deque<int> q;
    for(int i = 1; i <= n; i++)
    {
        while(q.size() && q.back() > a[i]) //新进入窗口的值小于队尾元素,则队尾出队列
            q.pop_back();
        q.push_back(a[i]);//将新进入的元素入队
        if(i - k >= 1 && q.front() == a[i - k])//若队头是否滑出了窗口,队头出队 
            q.pop_front();
        if(i >= k)//当窗口形成,输出队头对应的值
            cout << q.front() <<" ";
    }
    q.clear();
    cout << endl;

    //最大值亦然
    for(int i = 1; i <= n; i++)
    {
        while(q.size() && q.back() < a[i]) q.pop_back();
        q.push_back(a[i]);
        if(i - k >= 1 && a[i - k] == q.front()) q.pop_front(); 
        if(i >= k) cout << q.front() << " ";

    }
}
题目

  acwing 154 滑动窗口

  Acwing  829  模拟栈 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值