• 数据结构之栈和队列


      其实栈和队列是特殊的线性表,特殊之处在于插入和删除的位置受到限制,如果插入和删除只在一端进行,那么这就是栈,如果插入在尾部进行,删除在头部进行就是队列,下面我们具体来看看栈和队列的实现。

    1:栈

    定义:栈是一种特殊的线性表,其插入和删除只能在一端进行,允许操作的一端叫做栈顶,不允许操作的一端叫做栈底。插入元素我们叫做进栈(push),删除元素我们叫做出栈(pop)。下面我们定义栈的接口

    public interface SStack<T> {
        /**
         * 验证是否是空栈
         * @return
         */
        boolean isEmpty();
    
        /**
         * 进栈
         * @param x
         */
        void push(T x);
    
        /**
         * 出栈
         * @return
         */
        T pop();
    
        /**
         * 取栈顶元素
         * @return
         */
        T get();
    }

    2:顺序表实现栈

    要实现栈,首先我们需要一个变量来记录栈顶的位置,这个变量我们设置top。我们定义top初始值为-1,也就是说当栈空的时候top就是-1。栈的特点就是先进后出,那么进栈就很简单了,我们只需要让top++即可,然后取得时候只需要去top对应的元素,后进去的就先出来,先进去的后出来。代码如下

    private Object[] elements;
        private int top;//记录栈顶元素位置
    
        public SeqStack() {
            this(64);
        }
    
        public SeqStack(int size) {
            this.elements = new Object[size];
            this.top = -1;
        }
    
        public boolean isEmpty() {
            return this.top == -1;
        }
    
        public void push(T x) {
            if (x == null) {
                return;
            }
            if (this.top == this.elements.length - 1) {
                Object[] temp = this.elements;
                this.elements = new Object[2 * this.elements.length * 2];
                for (int i = 0; i < this.top; i++) {
                    this.elements[i] = temp[i];
                }
            }
            this.top++;
            this.elements[this.top] = x;
        }
    
        public T pop() {
            return this.top == -1 ? null : (T) this.elements[this.top--];
        }
    
        public T get() {
            return this.top == -1 ? null : (T) this.elements[this.top];
        }

    3:链式表实现栈

    链式实现更新的简单了,同样我们只需要用一个头节点来记录栈顶即可,如果头节点为空说明是空栈,出栈的时候只需求去头节点,入栈的时候,把新元素赋值给头元素,头元素的后继节点为原先的头节点即可。代码如下

      public Node<T> top;
        public LinkedStack(){
            top=new Node<T>(null,null);
        }
        public LinkedStack(T[] elements) {
            if (elements == null) {
                return;
            }
            for (int i = 0; i < elements.length; i++) {
                this.top = new Node<T>(elements[i], this.top);
            }
        }
    
        public boolean isEmpty() {
            return this.top == null;
        }
    
        public void push(T x) {
            if (x==null){
                return;
            }
            this.top=new Node<T>(x,this.top);
        }
    
        public T pop() {
            if (this.top != null) {
                T old = this.top.data;
                this.top = this.top.next;
                return old;
            }
            return null;
        }
    
        public T get() {
            return this.top == null ? null : this.top.data;
        }

    4:栈的应用

    我们经常写代码应该知道当我们写方法的时候少一个}编译器会立马报异常,现在我们考虑是如何实现的。

    假设这个一个字符串,我们遇到{号的时候把它放入栈中,如果遇到}号的时候就出栈,如果出栈的是{则说明一对{}匹配成功,如果栈空,或者不是{表示缺少与}相匹配的{符合,如果最后栈不为null,说明缺少}号。我们来实现下。

     public static boolean isValid(String str) {
            SStack<Character> characterSStack = new SeqStack<Character>(str.length());
            boolean result=true;
            for (int i = 0; i < str.length(); i++) {
                char ch = str.charAt(i);
                switch (ch) {
                    case '{':
                        characterSStack.push(ch);
                        break;
                    case '}':
                        boolean a = characterSStack.isEmpty();
                        boolean b = characterSStack.get() != '{';
                        if (a || b) {
                            result = false;
                        }
                        characterSStack.pop();
                        break;
                }
                if (!result) {
                    break;
                }
            }
            if (!characterSStack.isEmpty()) {
                result=false;
              }
            return result;
        }

     5:队列

    队列我们说了只可以在队列和队尾操作,队尾我们加入元素,队列我们删除元素,没有元素我们称为空队列。下面先定义接口

    public interface Queue<T> {
        /**
         * 验证队列是否为空
         * @return
         */
        boolean isEmpty();
    
        /**
         * 入队
         * @param x
         */
        void enQueue(T x);
    
        /**
         * 出队
         * @return
         */
        T deQueue();
    }

    6:顺序表实现队列

    既然我们分别是在头和尾进行操作,那么我们就需要2个变量值来记录队列和队尾。我们分别用front、rear分别表示对列和队尾,如果我们加入第一个一个元素,rear和front都+1,其他的我们只需要rear+1,如果出对列同样我们让front+1,这样一来就满足我们的条件,但是问题是如果加入5个元素后rear=4,然后在出对列2个元素那么front=1;这样一来我们的队列就无法全部运用上,出现了假溢出。所以我们考虑采用循环的队列模式。具体实现如下

    public class SeqQueue<T> implements Queue<T> {
        private Object[] elements;
        private int rear;//队尾
        private int front;//队头
    
        public SeqQueue() {
            this(64);
        }
    
        public SeqQueue(int length) {
            if (length <= 0) {
                return;
            }
            this.elements = new Object[length];
            this.front = rear = 0;
        }
    
        public boolean isEmpty() {
            return this.front == this.rear;
        }
    
        public void enQueue(T x) {
            if (x == null) {
                return;
            }
            if ((this.rear + 1) % this.elements.length == this.front) {
                Object[] temp = this.elements;
                this.elements = new Object[2 * this.elements.length * 2];
                int i = this.front, j = 0;
                while (i != this.rear) {
                    this.elements[j] = temp[i];
                    i = (i + 1) % temp.length;
                    j++;
                }
                this.front = 0;
                this.rear = j;
            }
            this.elements[this.rear] = x;
            this.rear = (this.rear + 1) % this.elements.length;
        }
    
        public T deQueue() {
            if (this.isEmpty()) {
                return null;
            }
            T old = (T) this.elements[this.front % this.elements.length];
            this.front = this.front + 1 * this.elements.length;
            return old;
        }

    7:链式实现对列

    链式的就比较简单了,如果是队尾的话我们直接可以把rear的后继节点赋值为新元素,然后在把rear节点赋值为新元素。但是我们要考虑的是空表插入,这个时候就没有后继节点了,这个时候我们直接把新元素赋值给front即可。如果出队就更简单了,直接获取front即可。我们看下源码

    public class LinkedQueue<T> implements Queue<T> {
        private Node<T> front;
        private Node<T> rear;
    
        public boolean isEmpty() {
            return this.front == this.rear && this.front == null;
        }
    
        public void enQueue(T x) {
            if (x == null) {
                return;
            }
            Node<T> p = new Node<T>(x, null);
            if (this.front == null) {
                this.front = p;
            } else {
                this.rear.next = p;
            }
            this.rear = p;
        }
    
        public T deQueue() {
            if (this.front == null) {
                return null;
            }
            T old = this.front.data;
            this.front = this.front.next;
            return old;
        }
  • 相关阅读:
    recon-ng打开后显示No modules enabled/installed
    mysql的floor()报错注入方法详细分析
    视频合并时使用python批量修改文件名
    ThinkPHP5框架引入的css等外部资源文件没有生效
    用session实现的用户登陆,客户端是怎样获取到cookie信息的
    关于Linux系统下基于Tomcat部署和升级war包的详细过程
    nginx代理的页面性能优化大全
    linux下MySQL数据库的定时备份与定时删除
    关于linux查询内存,CPU,存储空间和日志查询的的常用命令及参数讲解
    linux 查看cpu核心数
  • 原文地址:https://www.cnblogs.com/LipeiNet/p/6417752.html
Copyright © 2020-2023  润新知