算法-数据结构-基础数据结构(链表,邻接链表,栈,队列,单调栈/队列,堆)

链表

一种链式数据结构,前一个指向后一个,可以通过这种指针执行遍历操作
作用:
高效执行指定位置的插入元素操作o(1)

//数组模拟
const int N=1e5;
int e[N];//编号为i的边指向的节点
int ne[N];//ne代表编号为i的节点的下一条边
int idx;
void add_edge(int x,int val)//向x节点后添加一个节点值为val的
{
	e[++idx]=val;
	ne[idx]=ne[x];
	ne[x]=idx;
}
# 结构体
class node:
	def __init__(self,val=0):
		self.val=val
		self.ne=None
class linkedlist:
	def _init__(self):
		self.head=None
	def append(self,val)://在最后添加一个节点
		{
			newnode=node(val)
			if not self.head:
				self.head=newnode
			else:
				cur_node=self.head
				while cur_node.ne:
					cur_node=cur_node.ne
				cur_node.ne=newnode
}
	def head_insert(self,val):
	{
		newnode=node(val)
		newnode.ne=self.head
		self.head=newnode
}
	def insert_node(self,pos,val):
		{
		newnode=node(val)
		prev = self.head
        for i in range(pos - 1): 
            if not prev:
                return -1
            prev = prev.next

        if not prev:
            return -1
        newnode.next = prev.next
        prev.next = newnode
}
		

邻接链表
用于存储图的关系
链表只能存储一条链形式的图,而对其进行改造(加入h数组)可以存储一对多的关系。
关键
e数组 edge边
ne数组 next edge
h数组 当前节点上一个节点的

const int N=1e5+10;
int e[N],ne[N],h[N],idx;
memset(h,-1,sizeof h);
void add_adge(int a,int b)
{
	e[idx]=a,ne[idx]=h[a],h[idx]=++idx;
}

满足先进后出的数据结构,就像往坑里边丢土豆,必须拿出来上层的(后丢进去的)才能拿下层的
栈的顺序是天然倒序的:比如放入abc取出时就是cba,这种性质可以用于撤回操作
栈与树的关系也很重要,涉及到dfs,树的遍历顺序前中后序
栈的性质:保留最新操作的同时,保存到达最新操作的旧操作这个过程

//数组模拟栈
const int N=1e5+10;
int idx=0;
int stk[N];
void add(int val)
{
	stk[++idx]=val;
}
void rm()
{
	idx--;
}
//stl
#include<stack>

队列

//数列模拟
int l,r;
int q[N];
int idx;
void push_(int a)
{
	q[++r]=a;
}
void pop_()
{
	l++;
}

优先队列

一种二叉树状数据结构
父节点比子节点大/小
一个大根堆(父节点的值总是大于子节点)的删除逻辑是:与最后一个节点相交换然后执行down函数,因为直接删除会导致变成两个树。
插入的逻辑是:将新元素插入堆的底部然后进行up函数
关键是将对堆的所有更改操作都限定在堆底部

down函数调整的时候涉及到一个优先级问题,那就是父节点总和更大的子节点交换,否则交换后的结构不能保证父节点比子节点大

#include <iostream>
using namespace std;

const int N = 1e5 + 10;
int h[N];           // 堆数组(1-indexed)
int n = 0;          // 当前堆大小

void swap_(int x, int y) {
    int t = h[x];
    h[x] = h[y];
    h[y] = t;
}

// 向上调整
void up(int x) {
    while (x > 1 && h[x] > h[x / 2]) {
        swap_(x, x / 2);
        x /= 2;
    }
}

// 向下调整
void down(int x) {
    while (x <= n / 2) {  // 有至少一个孩子
        int child = x * 2;  // 默认左孩子
        // 如果右孩子存在且更大
        if (child + 1 <= n && h[child + 1] > h[child]) {
            child = child + 1;
        }
        if (h[x] >= h[child]) break;  // 堆性质已满足
        swap_(x, child);
        x = child;  // 下沉到孩子位置
    }
}

// 插入元素
void add(int val) {
    h[++n] = val;
    up(n);
}

// 删除堆顶
void pop_() {
    if (n == 0) return;
    swap_(1, n);
    n--;
    if (n > 0) down(1);  // 如果还有元素,调整
}
#面向对象编程
import heapq

class PriorityQueue:
    def __init__(self, max_heap=False):
        self.heap = []
        self.max_heap = max_heap  # True 表示大根堆

    def push(self, val):
        if self.max_heap:
            heapq.heappush(self.heap, -val)
        else:
            heapq.heappush(self.heap, val)

    def pop(self):
        if not self.heap:
            raise IndexError("pop from empty priority queue")
        val = heapq.heappop(self.heap)
        return -val if self.max_heap else val

    def top(self):
        if not self.heap:
            raise IndexError("top from empty priority queue")
        val = self.heap[0]
        return -val if self.max_heap else val

    def size(self):
        return len(self.heap)

    def empty(self):
        return len(self.heap) == 0

单调栈(栈的应用)

问题:找到某个元素的左边的最近的一个比它小的元素

int idx=-1;
int stk[N];
int target[N];
for(int i=0;i<n;i++)
{
	//先弹出
	while(idx!=-1&&stk[idx]>target[i])idx--;
	cout<<stk[idx];
	stk[++idx]=target[i];
}

单调队列

滑动窗口问题,要求输出一个滑动窗口里数组元素的最值(窗口大小不变为k)问所有可能答案是什么

核心思想是只维护可能的答案

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int a[N],q[N];
int tt=-1,hh;
int n,k;
int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    for(int i=0;i<n;i++)
    {
        if(hh<=tt&&q[hh]<i-k+1)hh++;
        while(hh<=tt&&a[q[tt]]>=a[i])tt--;
        q[++tt]=i;
        if (i >= k - 1) printf("%d ", a[q[hh]]);
    }

    printf("\n");
    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) printf("%d ", a[q[hh]]);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值