浅谈栈和队列

### 栈

栈模型

栈(stack)是限制对元素的插入(push)和删除(pop)只能在一个位置上进行的表,该位置是表的末端,叫做栈的栈顶(top)。

栈的基本操作只有两种,压入栈(push)和弹出栈顶(pop),且只能作用于栈顶。(只有栈顶元素是可访问的

你可以把栈结构理解成一个底部封闭,顶部打开的桶。最先进去的元素一定是最后才能取出,最晚进去的元素一定是最先取出。
因此栈又叫做LIFO(后进先出,Last In First Out)表。

栈的优势

栈的操作是常数时间的,而且是以非常快的常数时间。在某些机器上,push和pop都可以写成一条机器指令,现代计算机把栈操作作为它指令的一部分。因此栈是在计算机科学中继数组之后最基本的数据结构。

栈的实现

栈的实现分为数组实现和链表实现。

1` 链表实现
这里我们使用单链表来实现,定义一个first指针指向栈顶,栈的链表实现实际上是简化了单链表实现,具体实现看以下代码。

public class StackImplementByLinklist<AnyType> {
    public Node<AnyType> first;
    int size;
    //内部类定义node
    public class Node<AnyType>{
        AnyType data;
        Node<AnyType> next;
    }
     //初始化
    public void stack(){
        first=null;
        size=0;
    }

    public void push(AnyType a){
        Node oldNode=first;
        first=new Node();
        first.data=a;
        first.next=oldNode;
        size++;
    }

    public AnyType pop(){
        AnyType a=first.data;
        first=first.next;
        size--;
        return a;
    }

    public boolean isEmpty(){
        return size==0;
    }

    public int size(){
        return size;
    }
}

2` 数组实现
相比于链表实现,数组实现栈更加的常用。因为数组操作的常数时间极短,而且实现起来更加简单。

public class StackImplementByArray<AnyType> {
    AnyType[] arr;
    int size;
    public void stack(int capacity){
        arr=(AnyType[])new Object[capacity];
        size=0;

    }
    public void push(AnyType a){
        if(size==arr.length){
            changeArray(2*size+1);
        }
        arr[size]=a;
        size++;
    }
    public AnyType pop(){
        if(size==0){
            System.out.println("栈顶为空");
            System.exit(0);
        }
        AnyType a=arr[size-1];
        arr[size-1]=null;
        size--;
        return a;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public int size(){
        return size;
    }

    //由于数组大小是要先确定的,因此当数组满了后要扩大数组容量
    public void changeArray(int newCapacity){
        AnyType[] newArr=(AnyType[])new Object[newCapacity];
        for(int i=0;i<arr.length;i++){
            newArr[i]=arr[i];
        }
        arr=newArr;
    }

}

栈的应用

  • 平衡符号的检测

    编译器检查程序符号的语法错误,常常就是通过栈来实现的。

在编程时,我们经常会用到“ ( ),[ ],{ }," " ”这些符号,当这些符号不是配对出现的,编译器就会报错,编译就无法通过。

那么,编译器是怎么知道这些符号有没有配对出现的呢?它通常是这么处理的。

当遇到左符号,如“( [ { " ”这些,就把它压入一个准备好的栈;否则就弹出栈顶,检测当前符号是否与栈顶元素配对。一旦不能配对,直接退出报错。


### 队列

队列模型

wiki: 队列,又称为伫列(queue),是先进先出(FIFO, First-In-First-Out)的线性表。在具体应用中通常用链表或者数组来实现。队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作。队列的操作方式和堆栈类似,唯一的区别在于队列只允许新数据在后端进行添加。

队列模型就相当于我们日常生活的排队,在队伍的后面入队,在队伍的前端出队。

多种队列

队列一般分为普通的数组队列,链表队列和循环队列。

链表队列:长度一般是无限的,一般不存在溢出的可能性,用完就销毁,不会浪费内存空间。

普通的数组队列:长度一般是有限的,即数组长度。由于元素出队后其位置的内存空间并不会释放,因此会浪费大量的内存空间。

循环队列:特殊的数组队列,由于普通的数组的队列会浪费大量的内存空间,因此出现了循环队列。当循环队列的队尾指针到达数组末尾后,会重新回到数组起始位置,实现了对内存的重复利用。

队列的实现

1` 链表队列

public class QueueImplementByLinkList<AnyType> {
    Node first;//队首
    Node last;//队尾
    int size;
    public class Node{
        AnyType data;
        Node next;
        public Node(AnyType data,Node next){
            this.data=data;
            this.next=next;
        }
    }

    //初始化队列
    public void initqueue(){
        first=new Node(null,null);
        last=first;
        size=0;
    }

    //入队
    public void enqueue(AnyType a){
        if(size==0){
            last.data=a;
            size++;
            return;
        }
        Node oldlast=last;
        last=new Node(a,null);
        oldlast.next=last;
        size++;
    }

    //出队
    public AnyType dequeue(){
        if(size==0){
            System.out.print("队列为空");
            System.exit(0);
        }
        AnyType a=first.data;
        first=first.next;
        size--;
        return a;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public int size(){
        return size;
    }
}

2` 数组队列

public class QueueImplementByArray<AnyType> {
    AnyType[] arr;
    int first;
    int last;
    int size;
    //初始化
    public void ininqueue(int capacity){
        arr=(AnyType[])new Object[capacity];
        first=0;
        last=0;
        size=0;
    }
    public void enqueue(AnyType a){
        if(size==arr.length){
            changeArray(2*size+1);
        }
        arr[last++]=a;
        size++;
    }
    public AnyType dequeue(){
        if(size==0){
            System.out.println("队列为空");
            System.exit(0);
        }
        AnyType a=arr[first++];
        arr[first-1]=null;
        size--;
        return a;
    }
    public void changeArray(int newCapacity){
        AnyType[] newArr=(AnyType[])new Object[newCapacity];
        for(int i=0;i<arr.length;i++){
            newArr[i]=arr[i];
        }
        arr=newArr;
    }
    public boolean isEmpty(){
        return size==0;
    }
    public int size(){
        return size;
    }

}

3` 循环队列

public class CycleQueue {
    int[] arr;
    int start;//队首
    int end;//队尾
    int size=0;
    //初始化
    public void initqueue(int size){
        arr=new int[size];
        size=0;
        start=0;
        end=0;
    }

    //入队
    public void enqueue(int num){
        if(size>arr.length){
            System.out.println("队列已满");
            return;
        }
        if(end==arr.length){
            end=0;
        }
        arr[end++]=num;
        size++;
    }

    //出队
    public int dequeue(){
        if(size==0){
            System.out.println("队列为空");
            System.exit(0);
        }
        if(start==arr.length){
            start=0;
        }
        size--;
        return arr[start++];
    }

    public boolean isEmpty(){
        return size==0;
    }
    public int size(){
        return size;
    }
}

一点点总结

栈和队列是基本的数据结构,是对数组和链表的重新封装和扩展。由于它们的特性和执行速度,栈和队列被广泛的使用。

最后,不要为了使用数据结构而使用使用数据结构,要区分各种数据结构的使用场景,灵活地运用数据结构,可以事半功倍。

原文地址:https://www.cnblogs.com/sang-bit/p/11757553.html

时间: 2024-10-30 05:19:33

浅谈栈和队列的相关文章

浅谈栈、队列

所谓栈和队列其本质都是一种存储信息的方法,最主要的差别就是两者的存取方式不同,栈相当于是一个一端开口一端封闭的空心玻璃柱,每存入一个数据就是扔进一个与管口等粗的球,取出数据时只能取最上头的,也就是最后一个放进去的,并且当管中无球时,无法取数据:相对而言,队列相当于是一个两端开口的空心玻璃柱,每存入一个数据,就从后端插入一个与管口等粗的球,取数据时只能从前端取不能从后段取,同样当其中无球时无法取. 从上述介绍中可以发现两者各有优势,但队列有一个显著问题,但插入取出次数多时,可能仅有几个数据但存储却

浅谈栈帧(二)

接上一篇:浅谈栈帧(一) 上一篇我们简单说了一下关于堆栈与栈帧调用函数是如何调用的,堆栈中的数据是如何存储在内存中的,用了几个简单的实例去观察分析他. 这篇,我们从根本来思考一下堆栈这种东西: 其实在计算机的早期,电脑的内存是用是十分老实的,没错就是老实.他没有进行一些内存空间上的保护. 大家想想,在当内存空间不存在保护时,我们利用一个函数不断去改写计算机本身的内存,然后导致缓冲区溢出.这将使电脑崩溃,无法使用.因为内存不存在狡兔三窟,所以就老老实实的被病毒所平推了,就是是强拆,所以强拆是多么的

浅谈“栈和堆”

对于一些新人可能会不理解栈和堆是什么,在这里我简单介绍一下: 程序运行时,它的数据必须存储在内存中.一个数据项需要多大的内存.存储在什么地方.以及如何存储都依赖与该数据项的类型. 运行中的程序使用两个内存区域来存储数据:栈和堆. 首先,什么是“栈”? 栈是一个内存数组,是一个LIFO(last-in  first-out,后进先出)的数据结构.栈存储几种类型的数据: 某些类型变量的值 程序当前的执行环境 传递给方法的参数 栈的特征: 栈有如下几个普遍特征: 数据只能从栈的顶端插入和删除 把数据放

浅谈数据结构之链队列(六)

前面我们讲了队列的顺序存储结构,现在我们来看看队列的链式存储结构.队列的链式存储其实就是线性表的单链表结构,只不过它是尾进头出而已,通常我们把它简称为链队列.为了操作上的方便,我们将队头指针front指向链队列的头结点,而队尾指针rear则指向终端结点.注意:当队列为空时,指针front和rear都指向头结点. 在这里,我们再介绍一下循环队列.循环队列是为了避免数组插入与删除数据时需要移动数据而引入的,我们一般把队列的这种头尾相接的顺序存储结构称为循环队列.对于循环队列和链队列相比较来说,循环队

浅谈栈帧(一)

好久没有更新了,最近打算把近期所学的内容更新一下 今天说一说内存栈帧方面的吧=.= 关于栈帧:首先我们呢来了解一下它的基本概念. 1.堆栈:对于堆栈,其实就是我们程序进行执行,那么我们必须给它一块地盘,有了地基,才能够建筑出我们所需要的东西.没有地我们是无法去干任何事情的. 在计算机中,这个地盘其实就对于我们的内存空间.我们的程序其实就相当于施工队伍.我们所给出命令.然后对其进行指挥,完成我们布置的任务. (1)堆栈中有什么呢? 1.函数调用框架. 2.传递参数. 3.保存返回地址. 4.提供局

浅谈栈&amp;&amp;进制转换

利用stack实现进制转换 Stack.h #ifndef _STACK_H_ #define _STACK_H_ #include<iostream> #include<assert.h> using namespace std; typedef int ElemType; #define STACK_MAX_SIZE 100 #define HEX 2 typedef struct Stack { ElemType *base;//栈底指针 int top; //栈顶标识 in

浅谈 Celery 分布式队列

Q1: Django开发Web项目时遇到一个问题,如何解决大量用户在同一时间注册,短信发送延迟的问题? A1: ① 封装一个发送短信的函数 ② 创建进程.线程.协程调用发送短信的函数 Q2: 创建的进程.线程.协程和Django网站服务器在同一个电脑上,并且调用顺序也是不确定的 所以A1 OUT A2: Celery(异步任务队列): ① celery中的任务发出者,中间人和任务执行着可以在不同的电脑上 ② celery 中的任务会进行排序,先添加的任务先被worker执行 1. Celery的

浅谈栈

所谓栈,就是一种先进后出的数据结构. 何为先进后出?想象一个箱子,你往箱底塞了一本语文书,然后往语文书上放数学书.假设箱子底面积与书的面积相同,那么你想把先放进去的语文书拿出来,就必须得先把放在上面的数学书拿出来.所以"先进"的语文书与数学书比较是"后出"的. 在代码中一个栈由一个数组\(stk\)和一个变量\(top\)组成,数组存信息,\([1,top]\)的空间都被占用了,下一次放元素就只能放在\(top+1\)这个位置然后让\(top=top+1\).拿元素

浅谈算法和数据结构(1):栈和队列

浅谈算法和数据结构(1):栈和队列 2014/11/03 ·  IT技术                                         · 2 评论                                      ·  数据结构, 栈, 算法, 队列 分享到: 60 SegmentFault D-Day 2015 北京:iOS 站 JDBC之“对岸的女孩走过来” CSS深入理解之relative HTML5+CSS3实现春节贺卡 原文出处: 寒江独钓   欢迎分享原创