数据结构之栈和队列
  kIM7GUNpnV3x 2023年11月13日 39 0

一:物理结构和逻辑结构

除了数组和链表之外,常用过的数据结构还有很多,但大对数

*  都以数组或链表作为存储方式。数组和链表可以被看作数据存储

*  地‘物理结构“

*

* 什么是数据存储的物理结构呢?

* 如果把数据结构比作活生生的人,那么物理结构就是人的血肉

* 和骨骼,看得见,摸得着,实实在在。例如我们刚刚学过的数组和链表,都是内存中实实在在

* 存储结构

* 而在物质人体之上,还存在着人的思想和精神,它们看不见,摸不着。

* 看过电影《阿凡达》的:男主角的思想意识从认识一个瘦弱残疾的人类身上被移植

* 到一个高大威猛的蓝皮肤外星人身上,虽然承载着思想意识的肉身改变了,但是人格确实唯一的。

* 如果把物质层面的人体比作数据存储的物理结构,那么精神层面的人格则是

* 数据存储的逻辑结构。逻辑结构实是抽象的概念,它依赖于物理结构存在。

* 逻辑结构  线性结构:举例(顺序表、栈、队列)

*         非线性结构 举例(数、图)

*

* 物理结构  顺序存储结构 举例(数组)

*          链式存储结构 举例(链表)

二:栈和队列

什么是栈?
 * 假如有一个又细又长的圆筒,圆筒一端封闭,另一端开口,往圆筒里面放入兵乓球,先放入
 * 的靠近圆筒底部,后放入的靠近圆筒入口。
 * 那么,要想取出这些乒乓球,则只能按照和放入顺序相反的顺序来取,先取出
 * 后放入的,再取出先放入的,而不能把最里面最先放入的乒乓球优先取出
 * 。
 * 栈:是一种线性数据结构,它就像一个上图所示的放入乒乓球的圆通容器,栈中的元素只能
 * 先入后出(First Last Out,简称FILO)。最早进入的元素存放在位置叫做栈底,最后进入的元素存放在
 * 的位置叫作栈顶。
 *   栈这种数据结构既可以用数组来实现,也可以用链表来实现。
 *    栈底                栈顶
 *    3    5   1   4   9   6   null  null
 *
 *    栈的基本操作:
 *    1. 入栈
 *    入栈操作(push)就是把新元素放入栈中,只允许从栈顶一侧放入元素,新元素
 *    的位置将会成为新的栈顶。
 *
 *    2. 出栈操作
 *     出栈操作(pop)就是把元素从栈中弹出,只有栈顶元素才允许出栈
 *     ,出栈元素的前一个元素将会成为新的栈顶。
 *     由于栈操作的代码实现比较简单,这里就不在展示代码了。
 *     入栈和出栈只会影响到最后一个元素,不涉及其他元素的整体移动
 *     所以无论是以数组还是以链表实现,入栈、出栈的时间复杂度都是O(1)
 *
 * */


/**
 *   什么是队列
 *   要弄明白什么是队列?举一个例子来说明
 *   假如公路上有一条单行隧道,所有通过隧道的车辆
 *   只允许隧道入口驶入,从隧道出口驶出,不允许逆行。
 *
 *   因此,要想让车辆驶出隧道,只能按照它们驶入隧道的顺序,先驶入的车辆先驶出
 *   后驶入的车辆后驶出,任何车辆都无法跳过前面的车辆提前驶出的
 *
 *   队列是一种线性数据结构,它的特征和行驶车辆的单行隧道很相似。不同于栈的先入后出
 *   队列中的元素只能先入先出(First In First Out,简称FIFO)。队列的出口端叫做队头
 *   队列的入口端叫作队尾(rear)
 *   与栈类似,队列这种数据结构既可以用做数组来实现,也可以用链表来实现
 *    用数组实现时,为了入队操作的方便,把队尾位置规定为最后入队元素的下一个位置
 *    队列的数组实现如下:
 *    队头                         队尾
 *    3    5    1   4   9    6    null     null
 *
 *
 *    队列的基本操作:
 *    对于链表实现方式,队列的入队、出队操作和栈是大同小异的,对于实现来说,队列
 *    的入队和出队操作有了一些变化。
 *
 *    1. 入队
 *      入队(enqueue)就是把新元素放入队列中,只允许在队尾的位置放入元素,新元素
 *      的下一个位置将会成为新的的队尾。
 *
 *   2 出队
 *      出队操作(dequeue)就是把元素移出队列,只允许在队头一侧移出元素,出队元素
 *      的最后一个元素将会成为新的队头
 *    思考: 如果像这样不断的出队,队头左边的空间失去了作用
 *   那队列的容量岂不是越来越小了。
 *
 *    用数组实现的队列可以采用循环队列的方式来维持队列容量的恒定
 *
 *    循环队列:举例
 *    假设一个队列经过反复的入队和出队操作,还剩下两个元素,在“物理”
 *    上分布于数组末尾位置。这时又有一个新元素将要入队。
 *
 *    在数组不断做扩容的前提下,如何让元素入队并确定新的队尾位置呢?
 *    我们可以利用已出队的元素留下的空间,让队尾指针重新指回
 *    数组的首位。
 *    这样一来,整个队列的元素就“循环“起来了,在物理存储上,队尾的位置也可以
 *    在队头之前。当再有元素入队时,将其放入数组的首位,队尾指针继续后移即可
 *
 *    一直到(队尾下标+1) % 数组长度 = 队头下标时,代表队列真的已经满了。需要注意的是,
 *    队尾指针指向的位置永远空出1位,所以队列最大容量比数组长度小1。
 *
 * */

队列的基本操作举例:

// 循环队列的实现

private int[] array;
private int front;
private int rear;


public MyQueue(int capacity) {
    this.array = new int[capacity];
}



/**
 *
 * 入队
 * @param element 放入元素
 *
 *
 **/
public void enQueue(int element) throws Exception {
    if((rear + 1) % array.length == front) {
        throw new Exception("队列已满!");
    }
    array[rear] = element;
    rear =(rear + 1) % array.length;
}


/**
 * 出队
 *
 *
 * */

public int deQueue() throws Exception {
    if(rear == front) {
        throw new Exception("队列已空!");
    }
    int deQueueElement = array[front];
    front = (front + 1) % array.length;
    return deQueueElement;

}




/**
 *
 *
 * 输出队列
 *
 * */

public void output() {
    for(int i = front; i != rear; i = (i + 1) % array.length) {
        System.out.println(array[i]);
    }
}


public static void main(String[] args)  throws Exception{
    MyQueue myQueue = new MyQueue(6);
    myQueue.enQueue(3);
    myQueue.enQueue(5);
    myQueue.enQueue(6);
    myQueue.enQueue(8);
    myQueue.enQueue(1);
    myQueue.deQueue();
    myQueue.deQueue();
    myQueue.deQueue();
    myQueue.enQueue(2);
    myQueue.enQueue(4);
    myQueue.enQueue(9);
    myQueue.output();

                                              数据结构之栈和队列_链表

                 

循环队列不但可以充分利用数组的空间,还避免了数组元素整体移动的麻烦 , 至于入队和出队的时间复杂度,也同样是O(1)

三:栈和队列的应用

栈和队列的应用
* 1.栈的应用
* 栈的输出顺序和输入顺序相反,所以栈通常用于
*对”历史“的回溯,也就是逆流而上追溯”历史“
*例如实现递归的逻辑,就可以用栈来代替,因为栈可以回溯方法调用链
*
*栈还有一个著名的应用场景是面包屑导航,使用护在浏览界面时可以轻松追溯到上一级或更上一级
*页面。
*
* 2.队列的应用
*  队列的输出顺序和输入顺序相同,所以队列通常用于对”历史的回放“也就是按照”历史“的顺序把
*  ”历史“重演一遍。
*  例如:在多线程中,争夺公平锁的等待队列,就是按照访问顺序来决定线程在队列
*  中的次序的。
*  再如网络爬虫实现网站爬取时,也是把待抓取的网站的URL队列当中,
*  再按照存入队列的顺序来依次抓取和解析的。
*
*
*  3.双端队列:
*  双端数列这种数据结构,可以说是综合了栈和队列的优点,对双端队列来说,从队头
*  一端可以入队或者出队,从队尾一端也可以入队或者出队。
*
*
*  4.优先队列
*  还有一种队列,它遵循的不是先入先出,而是谁的优先级最高,谁先出队。
*
* 优先队列已经不属于线性数据结构的范畴了,它是基于二叉堆来实现的。关于优先队列的原理和使用情况后面再说
*
*
* */


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

推荐阅读
  zLxnEsMLk4BL   2023年11月19日   29   0   0 数组字符串数组名
  gBkHYLY8jvYd   2023年11月19日   23   0   0 #include数组ci
  X5zJxoD00Cah   2023年11月19日   18   0   0 数组单引号字符串
  gBkHYLY8jvYd   2023年12月10日   22   0   0 #include数组i++
kIM7GUNpnV3x