每日一题15:双端队列与自调整表

双端队列是一种插入和删除可以既可以在表头也可以表尾进行的一种数据结构,四种基本操作分别为:

push:在表头插入

pop:在表头删除

insert:在表尾插入

eject:在表尾删除

每一种操作的复杂度都为O(1)。通过组合不同插入和删除,双端队列可以作为栈使用,也可以作为队列使用:

#include "stdafx.h"
#include <iostream>

using namespace std;

struct deque_node
{
    int val;
    deque_node* next;
    deque_node* pre;
};

struct my_deque
{
    int count;
    deque_node* head;
    deque_node* tail;
};

my_deque* create_empty_deque()
{
    my_deque* deq = new my_deque;
    deq->head = NULL;
    deq->tail = NULL;
    deq->count = 0;
    return deq;
}

deque_node* create_deque_node(int val)
{
    deque_node* node = new deque_node;
    node->val = val;
    node->pre = NULL;
    node->next = NULL;
    return node;
}

void push(my_deque** deq,int val)
{
    deque_node* node = create_deque_node(val);
    if((*deq)->count == 0)
    {
        (*deq)->tail = node;
        (*deq)->head = node;
    }
    else
    {
        node->next = (*deq)->head;
        (*deq)->head->pre = node;
        (*deq)->head = node;
    }
    ++(*deq)->count;
}

bool pop(my_deque** deq,int& val)
{
    if((*deq)->count == 0) return false;
    if((*deq)->count == 1)
    {
        val = (*deq)->head->val;
        delete (*deq)->head;
        (*deq)->head = (*deq)->tail = NULL;
    }
    else
    {
        deque_node* p = (*deq)->head;
        (*deq)->head = p->next;
        (*deq)->head->pre = NULL;
        val = p->val;
        delete p;
    }
    --(*deq)->count;
    return true;
}

void insert(my_deque** deq,int val)
{
    deque_node* node = create_deque_node(val);
    if((*deq)->count == 0)
    {
        (*deq)->head = node;
    }
    else
    {
        (*deq)->tail->next = node;
        node->pre = (*deq)->tail;
    }
    (*deq)->tail = node;
    ++(*deq)->count;
}

bool eject(my_deque** deq,int& val)
{
    if((*deq)->count == 0) return false;
    if((*deq)->count == 1)
    {
        val = (*deq)->head->val;
        delete (*deq)->head;
        (*deq)->head = (*deq)->tail = NULL;
    }
    else
    {
        deque_node* p = (*deq)->tail;
        p->pre->next = NULL;
        (*deq)->tail = p->pre;
        val = p->val;
        delete p;
    }
    --(*deq)->count;
    return true;
}

void display(const my_deque* deq)
{
    deque_node* p = deq->head;
    while(p)
    {
        cout<<p->val<<‘ ‘;
        p = p->next;
    }
    cout<<endl;
}

void reverse_display(const my_deque* deq)
{
    deque_node* p = deq->tail;
    while(p)
    {
        cout<<p->val<<‘ ‘;
        p = p->pre;
    }
    cout<<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
    my_deque* deq = create_empty_deque();
    for (int i = 1; i < 6; ++i)
    {
        push(&deq,i);
    }
    display(deq);
    reverse_display(deq);
    cout<<deq->count<<endl;
    for (int i = 1; i < 6; ++i)
    {
        int val;
        if(pop(&deq,val))
            cout<<val<<‘ ‘;
    }
    cout<<endl;
    cout<<deq->count<<endl;

    for (int i = 1; i < 6; ++i)
    {
        insert(&deq,i);
    }
    display(deq);
    reverse_display(deq);
    cout<<deq->count<<endl;
    for (int i = 1; i < 6; ++i)
    {
        int val;
        if(eject(&deq,val))
            cout<<val<<‘ ‘;
    }
    cout<<endl;
    cout<<deq->count<<endl;
    return 0;
}

自调整表就像是一种规则的表,但是它的插入与删除操作都在表头进行,同时当任一个元素被find访问时,它就被移到表头而不改变其它元素的相对位置。基于链表实现的自调整表比较简单,基于数组实现的则需要更多的小心。

#include "stdafx.h"
#include <iostream>

using namespace std;

const int null_slot = -2;
const int end_slot = -1;

struct list_node
{
    int val;
    int next;
};

struct self_adjust_list
{
    int capacity;
    int size;
    int head;
    list_node* vals;
};

self_adjust_list* create(int capacity)
{
    self_adjust_list* sal = new self_adjust_list;
    sal->vals = new list_node[capacity];
    memset(sal->vals,0,capacity*sizeof(list_node));
    for (int i = 0; i < capacity; ++i)
    {
        sal->vals[i].next = null_slot;
    }
    sal->size = 0;
    sal->head = 0;
    sal->capacity = capacity;
    return sal;
}

bool find(self_adjust_list** sal,int val)
{
    if((*sal)->size == 0) return false;
    int cur = (*sal)->head;
    list_node* p = (*sal)->vals;
    int pre = -1;
    while(cur != end_slot && p[cur].val != val)
    {
        pre = cur;
        cur = p[cur].next;
    }
    if(cur == (*sal)->head) return true;
    if(cur != end_slot)
    {
        p[pre].next = p[cur].next;
        p[cur].next = (*sal)->head;
        (*sal)->head = cur;
        return true;
    }
    return false;
}

void push(self_adjust_list** sal,int val)
{
    if(find(sal,val)) return;

    if((*sal)->size == 0)
    {
        (*sal)->vals[0].val = val;
        (*sal)->vals[0].next = end_slot;

    }
    else
    {
        int i = 0;
        for (; i < (*sal)->capacity; ++i)
        {
            if((*sal)->vals[i].next == null_slot)
                break;
        }
        (*sal)->vals[i].next = (*sal)->head;
        (*sal)->vals[i].val = val;
        (*sal)->head = i;
    }

    ++(*sal)->size;
}

bool pop(self_adjust_list** sal,int &val)
{
    if((*sal)->size < 1) return false;

    list_node* p = &(*sal)->vals[(*sal)->head];
    val = p->val;
    if((*sal)->size > 1)
    {
        (*sal)->head = p->next;
        p->next = null_slot;
    }
    else
    {
        (*sal)->head = 0;
    }
    --(*sal)->size;
    return true;
}

int _tmain(int argc, _TCHAR* argv[])
{
    self_adjust_list* sal = create(20);
    for (int i = 1; i < 6; ++i)
        push(&sal,i);
    cout<<sal->size<<endl;
    for (int i = 10; i > 0; --i)
    {
        cout<<find(&sal,i)<<‘ ‘;
    }
    cout<<endl;
    for (int i = 1; i < 20; ++i)
    {
        int val;
        if(pop(&sal,val))
            cout<<val<<‘ ‘;
    }
    cout<<endl;
    cout<<sal->size<<endl;
    return 0;
}

时间: 2024-08-08 13:45:53

每日一题15:双端队列与自调整表的相关文章

经典算法题每日演练——第十九题 双端队列

原文:经典算法题每日演练--第十九题 双端队列 话说大学的时候老师说妹子比工作重要~,工作可以再换,妹子这个...所以...这两个月也就一直忙着Fall in love,嗨,慢慢调整心态吧, 这篇就选一个简单的数据结构聊一聊,话说有很多数据结构都在玩组合拳,比如说:块状链表,块状数组,当然还有本篇的双端队列,是的,它就是 栈和队列的组合体. 一:概念 我们知道普通队列是限制级的一端进,另一端出的FIFO形式,栈是一端进出的LIFO形式,而双端队列就没有这样的限制级,也就是我们可以在 队列两端进行

算法导论之八(10.1-5单数组实现双端队列)

算法导论第三版P131 题目: 10.1-5 栈插入和删除元素只能在同一端进行,队列的插入操作和删除操作分别在两端进行,与它们不同的,有一种双端队列(deque),其插入和删除操作都可以在两端进行.写出4个时间均为O(1)的过程,分别实现在双端队列插入和删除元素的操作,该队列使用一个数组实现的. 注意点: 1.左右端点指向的位置是类似于队列中的tail端点,是下一个插入操作的位置. 2.然后注意遍历的时候,左端点和右端点的位置关系,有两种可能,所以遍历的方式不一样. 代码: /* * 使用单数组

双端队列C实现代码 算法导论10.1-5 10.1-6 10.1-7

数组实现双端队列的时候注意区别判断上溢和下溢. 用两个栈实现队列,就相当于把两个栈底靠在一起(背靠背),一个栈用来出队列,一个栈用来进队列.这个队列的操作时间大部分时候是常数时间,除了出列的栈为空,需要把进列的栈全部转移过去,再出列.Back()操作和Pop()操作类似,也是这样. 而两个队列实现栈,队列轮流充当入栈和出栈的角色,而什么时候会改变角色呢,就是Pop()操作.Pop()操作先把一个队列中的所有元素全部出列并加入另外一个空队列中去,然后再出列(第二个队列). 实现代码为C #incl

关于双端队列 deque 模板 &amp;&amp; 滑动窗口 (自出)

嗯... deque 即为双端队列,是c++语言中STL库中提供的一个东西,其功能比队列更强大,可以从队列的头与尾进行操作... 但是它的操作与队列十分相似,详见代码1: 1 #include <cstdio> 2 #include <iostream> 3 #include <deque> 4 //实际上,引用queue头文件也可以,里面包含了deque头文件 5 6 using namespace std; 7 8 deque<int> dq; //定义

Vijos1834 NOI2005 瑰丽华尔兹 动态规划 单调双端队列优化

设dp[t][x][y]表示处理完前t个时间段,钢琴停留在(x,y)处,最多可以走多少个格子 转移时只需逆着当前倾斜的方向统计len个格子(len为时间区间的长度,len=t-s+1),如果遇到障碍就中断 转移过程可以用单调非递增的双端队列优化 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 const int maxN=202; 6 const int inf=0x3f3f3f3f

两个栈实现双端队列

一个笔试题,当时竟然没想出来,现在实现下 1 /* 2 用两个栈实现双端队列 3 栈s1,s2. 4 pushback()和popback(),必须在s2为空的情况,把s2的都放s1中 5 pushfront()和popfront(),必须是在s1为空,把s1的都给放到s2中 6 */ 7 #include <iostream> 8 #include <stack> 9 using namespace std; 10 template <typename T> 11 c

UVa 210 Concurrency Simulator (双端队列+模拟)

题意:给定n个程序,每种程序有五种操作,分别为 var = constant(赋值),print var (打印), lock, unlock,end. 变量用小写字母表示,初始化为0,为程序所公有(一个程序里对某个变量修改可以会影响其他程序里的这个变量), 常数小于100(也就是说最多两位数). 每个时刻都只能有一个程序处于运行状态,其他的都在等待,上述五种操作用时分别是t1, t2, t3, t4, t5.运行中的程序, 每次最多能运行q个时间,当q个时间被用完后,它会被放在等待队列的尾部,

lintcode 二叉树的锯齿形层次遍历 (双端队列)

题目链接: http://www.lintcode.com/zh-cn/problem/binary-tree-zigzag-level-order-traversal/ 二叉树的锯齿形层次遍历 给出一棵二叉树,返回其节点值的锯齿形层次遍历(先从左往右,下一层再从右往左,层与层之间交替进行) 样例 给出一棵二叉树 {3,9,20,#,#,15,7}, 3 / 9 20 / 15 7 返回其锯齿形的层次遍历为: [ [3], [20,9], [15,7] ] 思路: 我们用双端队列模拟一下这个过程

【Weiss】【第03章】练习3.26:双端队列

[练习3.26] 双端队列(deque)是由一些项的表组成的数据结构,对该数据结构可以进行下列操作: Push(X,D):将项X插入到双端队列D的前端. Pop(D):从双端队列D中删除前端项并返回. Inject(X,D):将项X插入到双端队列D的尾端. Eject(D):从双端队列D中删除尾端项并返回. 编写支持双端队列的例程,每种操作均花费O(1)时间. Answer: 相当简单的题目,把改一改双向链表就可以了. 测试代码: 1 #include <iostream> 2 #includ