数据结构——1

本文包括集中常见的数据结构,如链表,队列,栈。

 链表

 单链表

单链表是一种基本的链表,支持基本的插入,删除操作。

const int N = 100010;
int idx,ne[N],head,value[N];
 
void init()//初始化
{
    idx=0;
    head=-1;
}
 
void insert(int x)//在头结点后插入
{
    value[idx]=x;
    ne[idx]=head,head=idx,idx++;
}
 
void insert_m(int k,int x)//在下标为k的位置后插入x
{
    value[idx]=x,ne[idx]=ne[k],ne[k]=idx++;
}
 
void remove_(int k)//删除头结点
{
    ne[k]=ne[ne[k]];
}
 

我们定义链表的头节点为head,idx为当前用到节点的值,e[N]数组用于存放结点的值,ne[N]数组用于存放当前结点的next指针,初始化操作我们让head为-1,idx为0。空结点下表为-1。

插入操作

如果我们希望把一个数字插到头结点,我们可以分为两步(先将x的值赋值给e[idx[,第一步将要插入的结点指向数值为3的这个结点,也就是让ne[idx]=head,head就是指向数值为3的结点的指针,然后将head原先的指针断开,再将idx加一,也就是head=idx++。

如果是插入到下标为k的结点,如图先让e[idx]=x,将x的值赋给这个插入结点然后第一步让结点指向结点3,然后将2号结点的指针指向插入结点即可完成插入。要注意的是,在第k个插入结点后插入的操作必须要先将插入结点指针指向3结点,因为如果先将2指向插入结点,3号结点就找不到了

双链表

 双链表的操作与单链表差别不大,主要是为了更快的寻找到前驱元素增加的左指针,在初始化中我们定义下标为0的为head结点,下标为1的为tail结点,刚刚开始我们的idx就为2,因为我们刚刚开始双链表中就有两个结点        

const int N=1e6+10;
int value[N],l[N],r[N],idx;
void Init()//初始化双链表,我们让下标为0的点为头结点,下标为1的点是尾结点 
{
	r[0]=1;
	l[1]=0; 
	idx=2;
}
void add(int k,int x)//在编号为k的点的右边插入一个数
 	{
 		value[idx]=x;
		l[idx]=k;
		r[idx]=r[k];
		l[r[k]]=idx;
		r[k]=idx;
		idx++;
	}
	void remove(int k )//删除第k个点 
	{
			r[l[k]]=r[k];
			l[r[k]]=l[k];
	} 

栈是一个操作受限的线性表,其只支持在栈顶进行入栈和出栈操作(first-in last-out)

const int N=1e6+10;
int stack[N],tt;
void Init()//栈的初始化
{
	tt=-1;
}
void insert(int x)//入栈
{
	stack[++tt]=x;;
}
void pop()//出栈
{
	tt--;
}
int query()//返回栈顶元素
{
	return stack[tt];
}
bool judge()//判断栈是否为空
{
	if(tt>=0)
	{
		printf("Not Empty"); 
	}
	else
		printf("Empty");
}

单调栈(模板题)

单调栈的主要应用有:求数列中每个元素X的右边第一个大于元素X的新元素Y
求数列中每个元素X的左边第一个小于元素X的新元素Y
给一个数组,返回一个大小相同的数组,返回的数组的第i个位置的值是对于原数组中的第i个元素,至少往右走多少步,才能遇到一个比自己大的元素
给一个数组,返回一个大小相同的数组,返回的数组的第i个位置的值是对于原数组中的第i个元素,至少往左走多少步,才能遇到一个比自己小的元素
如果不存在,则输出-1

 具体可以看这位大佬的bolg

一下是求一个数组中一个数组左边距离最近的小于它的数的题解。

#include <iostream>
using namespace std;
const int N=10000;
int stack[N],tt;//栈和栈顶元素 
int main(){
	int n; 
	cin>>n;
	for(int i=0;i<n;i++)
	{
		int x;
		cin>>x;
		while(tt&&stack[tt]>=x) tt--;
		if(tt) cout<<stack[tt]<<" ";
		else cout<<"-1"<<" ";
		stack[++tt]=x;
	 } 
	 return 0;
	
} 

队列

队列是一种特殊线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

using namespace std;
const int N=1e6+10;
int queue[N],hh,tt;
void Init()//队列的初始化
{
	hh=-1;
	tt=-1;
}
void push(int x)//入队
{
	queue[++tt]=x;
 } 
 void pop()//出队
 {
 	hh++;
 }
 int get()//返回队头元素
 {
 	return  queue[hh]; 
 }

单调队列(滑动窗口)

#include<cstdio>
#include<iostream>
 
using namespace std;
 
const int N = 1e6+10;
 
int a[N],q[N],hh = 0,tt = -1;
 
int main()
{
    int n,k;
    cin >> n >> k;
    for(int i=0;i<n;i++)scanf("%d",&a[i]);
    
    for(int i=0;i<n;i++)
    {
        if(hh <= tt && (i - k + 1) > q[hh])hh++;
        while(hh <= tt && a[i] <= a[q[tt]])tt--;
        q[++tt] = i;
        if(i-k+1>=0)
            printf("%d ",a[q[hh]]);
    }
    
    puts("");
    
    hh = 0,tt = -1,q[0] = 0;
    
    for(int i=0;i<n;i++)
    {
        if(hh <= tt && (i - k + 1) > q[hh])hh++;
        while(hh <= tt && a[i] >= a[q[tt]])tt--;
        q[++tt] = i;
        if(i-k+1>=0)
            printf("%d ",a[q[hh]]);
    }
    
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值