学习总结(数据结构:栈和队列)

转载请标明出处,谢谢!
https://www.jianshu.com/p/8cb602ef4e21

关联文章
冒泡、选择排序 https://www.jianshu.com/p/176b0b892591
栈和队列 https://www.jianshu.com/p/8cb602ef4e21
顺序表、单双链表 https://www.jianshu.com/p/3aeb5998e79e
二叉树 https://www.jianshu.com/p/de829eab944c
图论 https://www.jianshu.com/p/cf03e51a3ca2

栈和队列

栈:只允许在表的末端进行插入和删除的线性表。基于数组存储表示的栈称为 顺序栈,基于链表的存储表示的栈称为链栈

image

栈的存储特性可以理解成子弹压入弹夹中。先压入的子弹总数在最后才弹出。因此栈也称为先进后出(LIFO, Last In First Out) 的线性表

下面用代码表示下:采用链式栈的方式

public class Node<T> {
        T data;//结点数据
        Node next;//指针

        private Node(T data) {
            this.data = data;
        }
        public Node() {
        }
    }

    public class Stack {
        private Node stackTop; //栈顶
        private Node stackBottom; //栈底

        public Stack(Node stackTop, Node stackBottom) {
            this.stackTop = stackTop;
            this.stackBottom = stackBottom;
        }

        private Stack() {
        }
    }

入栈:将原本栈顶指向的节点交由新节点来指向,栈顶指向新加入的节点

  /**
     * 入栈
     *
     * @param stack   原本的栈
     * @param newNode 新的结点
     */
    public void pushToStack(Stack stack, Node newNode) {
        /*新节点变成栈顶*/
        newNode.next = stack.stackTop;
        stack.stackTop = newNode;

    }

空栈:如果栈顶和栈底指向相同,说明是空栈

/**
     * 判断是否是空栈
     *
     * @param stack
     * @return
     */
    public boolean isEmpty(Stack stack) {
        return stack.stackTop == stack.stackBottom;
    }

遍历:栈顶指针不断向下移,直到到达栈底。为了避免影响原栈,使用临时结点指向stackTop并且随之一起移动。

  /**
     * 栈的遍历
     *
     * @param stack
     */
    public void traverse(Stack stack) {
        Node temp = stack.stackTop;
        /*如果空栈不执行*/
        if (isEmpty(stack)) {
            System.out.println("空栈");
            return;
        }

        while (!isEmpty(stack) && temp != null) {
            System.out.println(temp.data);
            temp = temp.next;

        }

    }

出栈:将栈顶指针向下移动一位

 /**
     * 出栈
     *
     * @param stack
     */
    public void popStack(Stack stack) {
        if (isEmpty(stack)) {
            return;
        }
        stack.stackTop = stack.stackTop.next;

    }

清空栈:实际上就是不断的出栈,直到到达栈底

 /**
     * 清空栈
     *
     * @param stack
     */
    public void clearStack(Stack stack) {
        if (isEmpty(stack)) {
            return;
        }

        while (!isEmpty(stack)) {
            popStack(stack);
        }

    }

测试:

  @Test
    public void test() {
        Stack stack = new Stack();
        for (int i = 0; i < 5; i++) {
            pushToStack(stack, new Node("我是结点" + i));
        }
        System.out.println("栈的长度 = "+ getLength(stack));
        traverse(stack);

        popStack(stack);
        popStack(stack);
        popStack(stack);
        System.out.println("------出栈后-------");

        traverse(stack);

        clearStack(stack);
        System.out.println("------清空栈-------");
        traverse(stack);
        
    }
image.png

队列

队列:队列是限定数据存储位置的一种线性表,它允许在一端插入,再另一端删除。允许插入的一端叫队尾,允许删除的一端叫做队头。

image

队列基于数组的存储表示称为顺序队列。是利用一个一维数组 array[maxLength]表示存储的.并且利用了2个指针front和rear分别表示队头和队尾的位置。

如图表示:当front等于rear时,此队列不是还剩一个元素,而是空队列。

image

当有数据插入的时候,数据插入的位置是当前rear的位置,而rear的值就要前进一位,因为rear永远指向下一个数据的存储位置。

image

当数据删除的时候 首先要把当前front指向位置的数据记录下来,然后front的指向位置就要+1,最后把记录的元素返回。因为front指向的位置永远都是对头元素

image

那么问题来了,rear永远指向下一个位置元素的存储位置,那么如果出现上图的情况不就是存储的内存溢出了吗? 实际上这个溢出是”假溢出“

因为我们可以发现 再数据的前面实际上还有空位置可以利用。根据这种情况,为了充分利用资源空间从而引出了循环队列

image

用2个公式表示

队头指针进1 : front = (front+1)%maxLength ;

队尾指针进1 : rear = (rear+1)%maxLength ;

如果循环队列读取元素的速度大于存入的速度,队头指针很快就赶上队尾指针,一旦front == rear 则变成空队列,反之,如果存入元素的速度大于读取的,队尾指针赶上队头指针,如果队列满就不能再添加数据了。为了区分空队列和满队列,用(rear+1)%maxLength == front来表示满队列,用 rear== front表示空队列。

同样的用代码测试一下:用顺序队列表示下

 private final static int MAX_LENGTH = 5;

    public class Queue {
        public String[] array;
        public int front;
        public int rear;

        public Queue() {
            front = 0;
            rear = 0;
            array = new String[MAX_LENGTH];
        }
    }

判断是否满队列 :用公式rear = (rear+1)%maxLength ==front;

 /**
     * 判断是否满队列
     *
     * @param queue
     * @return
     */
    public boolean isFull(Queue queue) {
        return (queue.rear + 1) % MAX_LENGTH == queue.front;
    }

判断是否是空队列:用公式 rear== front


    /**
     * 判断是否是空队列
     *
     * @param queue
     * @return
     */
    public boolean isEmpty(Queue queue) {
        return queue.rear == queue.front;
    }

入队列 :数据插入的位置是当前rear的位置,而rear的值就要前进一位,因为rear永远指向下一个数据的存储位置。

/**
     * 添加数据
     *
     * @param queue
     * @param data
     */
    public void enQueue(Queue queue, String data) {
        if (isFull(queue)) {
            System.out.println("满队列");
            return;
        }

        queue.array[queue.rear] = data;
        queue.rear = (queue.rear + 1) % MAX_LENGTH;


    }

删除数据 :front的指向位置就要向前一位

 /**
     * 删除数据
     *
     * @param queue
     */
    public void delQueue(Queue queue) {
        if (isEmpty(queue)) {
            System.out.println("空队列");
            return;
        }
        queue.front = (queue.front + 1) % MAX_LENGTH;

    }

清空队列:

 /**
     * 清空数据
     *
     * @param queue
     */
    public void clear(Queue queue){
        if (isEmpty(queue)) {
            System.out.println("空队列");
            return;
        }

        while (!isEmpty(queue)){
            System.out.println(queue.array[queue.front]);
            queue.front = (queue.front+1) % MAX_LENGTH;
        }
    }

遍历队列:使用临时变量防止破坏源数据

/**
     * 遍历
     *
     * @param queue
     */
    public void traverse(Queue queue) {
        if (isEmpty(queue)) {
            System.out.println("空队列");
            return;
        }

        int tempFront = queue.front;
        while (tempFront!= queue.rear) {
            System.out.println(queue.array[tempFront]);
            tempFront = (tempFront + 1) % MAX_LENGTH;
        }
    }

测试一下:

 @Test
    public void test() {
        Queue queue = new Queue();
        enQueue(queue, "1");
        enQueue(queue, "2");
        enQueue(queue, "3");
        traverse(queue);

        System.out.println("删除一个数据后");
        delQueue(queue);
        traverse(queue);

        System.out.println("清空数据后");
        clear(queue);
        traverse(queue);
        
    }

image.png

最近发现了一个问题,即当前长度如果是5,当添加第5个数据的时候就已经提示队列满了,因为(rear+1)%5 = (4+1)%5 = 0 而此时front(都不出队的情况下)=0 这个和判空的条件front=rear实际是冲突的,那么实际情况真是这样吗?
其实为了区分这种情况,循环队列判断满队列实际上是牺牲了一个空间来和空队列做区分。

如果新元素成功入队的话,我们的tail也等于2,那么此时就成了 tail == front ,一开始我们提到过,当队列为空的tail == front,现在呢,如果队列为满时tail也等于front,那么我们就无法区分,队列为满时和队列为空时收的情况了.
所以,在循环队列中,我们总是浪费一个空间,来区分队列为满时和队列为空时的情况,也就是当 ( tail + 1 ) % capacity == front的时候,表示队列已经满了,当front == tail的时候,表示队列为空。

图片.png

原文:https://www.php.cn/java-article-416578.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容

  • 栈与列队 栈是限定仅在表尾进行插入和删除操作的线性表 队列是只允许在一端进行插入操作、而在另一端进行删除操作的线性...
    Longshihua阅读 1,135评论 0 3
  • 这里我们只介绍线性表中 存储结构不同的 顺序表 和 链表,以及操作受限的 栈 和 队列 。 数据结构与算法系列文章...
    且行且珍惜_iOS阅读 1,696评论 0 5
  • 栈是限定仅在表尾进行插入和删除操作的线性表。表尾端称为栈顶,表头端称为栈底。不含元素的空表称为空栈。栈是后进先出的...
    yinxmm阅读 1,812评论 0 0
  • 数据结构 第7讲 循环队列 过了一段时间,小张再也受不了...
    rainchxy阅读 8,985评论 4 16
  • 你说过的话恍如昨日 你的习惯以及最初的梦想 都替你记着 ——《你的婚礼》 电影里有句很有道理的话,是说...
    血疼阅读 704评论 4 2