zoukankan      html  css  js  c++  java
  • 队列中取最大值操作问题

    题目描述:

    假设有这样一个拥有3个操作的队列:

    1 Enqueue(v): 将v加入队列

    2 DeQueue:使队列中的队首元素删除并返回此元素

    3 MaxElement:返回队列中的最大元素

    请设计一种数据结构和算法,让MaxElement操作的时间复杂度尽可能地低。

    队列是遵守“先入先出”原则的一种复杂数据结构。其底层的数据结构不一定要用数组来实现,还可以使用其他特殊的数据结构来实现,以达到降低MaxElement操作复杂度的目的。

    分析与解法:

    解法一

    这个问题的关键在于取最大值的操作,并且考虑但队列里面的元素动态增加和减少的时候,如何能够非常快速地把最大值取出。

    虽然,最直接的思路就是按传统方式来实现队列。利用一个数组或链表来存储队列的元素,利用两个指针分别指向队列的队首和队尾。如果采用这种方法,那么MaxElement操作需要遍历队列的所有元素。在队列的长度为N的条件下,时间复杂度为O(N)。

    解法二

    根据取最大值的要求,可以考虑用最大堆来维护队列中的元素。堆中每个元素都有指针指向它的后续元素。这样,堆就可以很快实现返回最大元素的操作。同时,我们也能保证队列的正常插入和删除。MaxElement操作其实就是维护一个最大堆,其时间复杂度为O(1)。而入队和出队操作的时间复杂度为O(lgN)

    开始不太能理解,后来想想好像是这样的,比如,队列是先进先出的,所以用一种数据结构来记录元素的进出顺序,而使用最大堆来维持找到最大值的效率。假如使用queue来存放所有的数据,当入队的时候直接插入队尾,而最大堆也需要将加入的值放在堆的最后,然后进行调整,直到满足最大堆。如果是进行访问最大值,可以直接访问堆顶的元素。如果是进行出队操作,从队列的首部删除该元素,并在最大堆中找到该元素,删除之后,进行调整。这样既能够达到满足队列的“先进先出”,也能满足在O(1)的条件下访问到最大值。

    解法三

    曾经做过一种类似的题目是最小栈,也就是在O(1)的情况下访问到栈中的最小元素。如是想到也可以使用这种方式来实现优先队列,

    如果使用两个数组分别存放,第一个数组按进入的顺序存放所有的元素,另一个数组中存放最大值的下标,另外还用一个变量记录当前的最大值下标。

    实现代码:

    复制代码
    class stack
    {
    public:
        stack()
        {
            stackTop=-1;
            maxStackItemIndex=-1;
        }
        void push(Type x)
        {
            stackTop++;
            if(stackTop>=Max)
            ;  //栈满
            else
            {
                stackItem[stackTop]=x;
                if(x>Max())
                {
                    link2NextMaxItem[stackTop]=maxStackItemIndex;
                    maxStackItemIndex=stackTop;
                }
                else
                    link2NextMaxItem[stackTop]=-1;
             }
        }
        Type Pop()
        {
            Type ret;
            if(stackTop<0)
                ThrowException();  //已经没有元素来,所以不能pop
            else
            {
                ret=stackItem[stackTop];
                if(stackTop==maxStackItemIndex)
                {
                    maxStackItemIndex=link2NextMaxItem[stackTop];
                }
                stackTop--;
            }
            return ret;
        }
        Type Max()
        {
            if(maxStackItemIndex>=0)
                return stackItem[maxStackItemIndex];
            else
                return -INF;
        }
    private:
        Type stackItem[MAXN];
        int stackTop;
        int link2NextMaxItem[MAXN];
        int maxStackItemIndex;
    };

    这里,维护一个最大值的序列来保证Max操作的时间复杂度为O(1),相当于用空间复杂度换取了时间复杂度。

    如果能够用栈有效第实现队列,而栈的Max操作又很容易,那么队列的Max操作也就能有效地完成了。

    一 内存泄漏

    1 C++内存泄漏

    在C程序中使用malloc()分配内存,使用free()来释放内存,当未释放不再使用的内存时就会出现“内存泄漏”

    在C++程序中使用new()分配内存,使用delete()释放内存,当未释放不再使用的内存时就会出现“内存泄漏”

    2 避免内存泄漏

    每次调用malloc分配内存时,注意在以后要调用想要的free来释放它。

    3 检测内存泄漏

    内存泄漏的症状就是罪魁进程的速度会减慢。原因是体积大的进程更有可能被系统换出,让别的进程运行,而且大的进程在换入换出时花费的时间也更多。

    观察内存泄漏是一个两步骤的过程。首先,使用swap命令观察还有多少可用的交换空间,过一两分钟键入该命令两到三次,看看可用的交换区是否在减少。还可以使用其他一些工具入netstat、vmstat等。第二个步骤是确定可疑的进程,看看它是不是该为内存泄漏负责,你可能已经知道哪个进程是罪魁祸首,不然可以使用ps -lu 用户名命令来显示所有进程的大小。

    二、什么是大端和小端

            Big-Endian和Little-Endian的定义如下:
    1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
    2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
    举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:

    1)大端模式:

    低地址 -----------------> 高地址
    0x12  |  0x34  |  0x56  |  0x78

    2)小端模式:

    低地址 ------------------> 高地址
    0x78  |  0x56  |  0x34  |  0x12

    可见,大端模式和字符串的存储模式类似。

    3)下面是两个具体例子:

    16bit宽的数0x1234在Little-endian模式(以及Big-endian模式)CPU内存中的存放方式(假设从地址0x4000开始存放)为:
     
    内存地址 小端模式存放内容 大端模式存放内容
    0x4000 0x34 0x12
    0x4001 0x12 0x34

    32bit宽的数0x12345678在Little-endian模式以及Big-endian模式)CPU内存中的存放方式(假设从地址0x4000开始存放)为:

    内存地址 小端模式存放内容 大端模式存放内容
    0x4000 0x78 0x12
    0x4001 0x56 0x34
    0x4002 0x34 0x56
    0x4003 0x12 0x78
     

     4)大端小端没有谁优谁劣,各自优势便是对方劣势:

    小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
    大端模式 :符号位的判定固定为第一个字节,容易判断正负。

  • 相关阅读:
    spring(2)
    Android之滑动按钮实现Demo
    spring(1)
    spring(4)
    Android之ImageSwitch控件
    使用非阻塞ServerSocketChannel、SocketChannel代替ServerSocket和Socket
    Android之界面刷新(invalidate和postInvalidate使用)
    Android之改变控件的背景及形态
    Android之获得内存剩余大小与总大小
    OpenCV中矩阵的归一化
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8461146.html
Copyright © 2011-2022 走看看