• 数据结构2——堆栈/队列


    前言:之前介绍了线性表,今天来介绍一下堆栈/队列。

    1:堆栈主要特点就是只允许固定的一段插入和删除。

    采用的是先进后出的方式   如果洗盘子,再比如我们计算机中的递归调用 ,判断字符串是否为回文字符串,利用堆栈来计算算术表达式

     我们只能从栈顶取出元素。而且元素也必须从栈顶进入。

     

    同时堆栈又分为:顺序堆栈和链式堆栈

    1.1.:顺序堆栈

    数据集合:主要是通过数组的形式存储元素。

    操作集合:可以定义为一个接口

    1 public interface Stack {
    2     public void push(Object object);      //进栈
    3     public Object pop();                  //出栈
    4     public Object getTop();                //获取栈顶的元素
    5     public boolean notEmpty();            //判断栈是否为空
    6 }

    (2)顺序堆栈的具体实现

     1 package com.hone.stack;
     2 
     3 public class SeqStack implements Stack{
     4     final int defaultSize=10;        //默认元素个数
     5     int top;                        //栈顶位置  
     6     Object[] stack;                    //数组对象
     7     int maxStackSize;                //最大数据元素的个数
     8     
     9     //创建一个构造方法可以初始化defaultSize
    10     public SeqStack() {
    11         initiate(defaultSize);
    12     }
    13     
    14     //创建一个带参数的构造函数,用于
    15     public SeqStack(int sz){
    16         initiate(sz);
    17     }
    18     //初始化maxStackSize top stack 对象
    19     private void initiate(int sz) {
    20         maxStackSize=sz;
    21         top=0;
    22         stack=new Object[sz];
    23     }
    24     
    25     /*
    26      * 进栈
    27      */
    28     @Override
    29     public void push(Object obj) {
    30         if (top==maxStackSize) {
    31             System.out.println("堆栈已满!");
    32         }
    33         stack[top]=obj;            //保存刚传进来的元素并且马上建立一个空的栈顶
    34         top++;                        //产生新栈顶位置(只有栈顶没有元素)  
    35     }
    36     //出栈
    37     @Override
    38     public Object pop() {
    39         if (top==0) {
    40             System.out.println("堆栈已空");
    41         }
    42         top--;                            //产生原来栈顶位置
    43                                //减1的原因(因为这里面加入了一个元素之后都会新开辟一个栈顶,所以无论怎么样都会有一个空的栈顶)
    44         return stack[top];                //返回原来栈顶的元素
    45     }
    46   //获得栈顶位置的元素
    47     @Override
    48     public Object getTop() {
    49         return stack[top-1];            //返回原栈顶元素
    50     }
    51   //判断栈是否为空
    52     @Override
    53     public boolean notEmpty() {
    54         return (top>0);
    55     }
    56 }

     1.2:链式节点

    首先需要创建节电类,包含元素和下一个结点

     1 /*
     2  * 整个类使用于封装节点的类,包含两个元素一个是element/next
     3  */
     4 public class Node {
     5     Object element;
     6     public Node next;
     7 
     8     // 定义一个构造函数用于结点
     9     public Node(Node nextval) {
    10         next = nextval;
    11     }
    12 
    13     // 定义一个构造函数用于初始化结点和元素
    14     public Node(Object o, Node nextval) {
    15         element = o;
    16         next = nextval;
    17     }
    18 
    19     public Object getElement() {
    20         return element;
    21     }
    22 
    23     public void setElement(Object element) {
    24         this.element = element;
    25     }
    26 
    27     public Node getNext() {
    28         return next;
    29     }
    30 
    31     public void setNext(Node next) {
    32         this.next = next;
    33     }
    34     
    35     //将获得的元素转化为String类型
    36     public String toString(){
    37         return element.toString();
    38     }
    39 }

    链式栈的实现类:这里面只需要一个head节点就可以了

    package com.hone.stack.lin;
    
    
    import com.hone.stack.Stack;
    
    public class LinStack implements Stack{
        Node head ;                //获得链式堆栈的头节点
        int size;                //结点的个数
        
        //定义一个构造函数用于初始化head结点以及size的大小
         public LinStack() {
             head=null;
             size=0;
        }
    
         //入栈  从头部开始插入
        @Override
        public void push(Object object) {
            head=new Node(object, head);    
            size++;
        }
        //出栈,从头部开始
        @Override
        public Object pop() {
            if (size==0) {
                System.out.println("堆栈为空");
            }
            Object object=head.getElement();      //这里面element行不行呢?
            head=head.next;
            size--;
            return object;
        }
        //获得头部顶端的一个元素
        @Override
        public Object getTop() {
            return head.getElement();                //这里面Element行不行?
        }
        //判断栈是否为空,只需要判断head结点是否为空就可
        @Override
        public boolean notEmpty() {
            return head!=null;
        }
    
    }

     2:队列

    队列的主要特点是从一端进,另一端出。队尾入,队头出。因此形成了先进先出的存储模式。

    如果将队头和队尾连接起来就成了循环队列。

    在队列中必须是队头为head节点,因为只有head节点才有next节点,否则,在出队的时候队尾无法找到rear.next节点

    其次,由于顺序队列很容易存在“假溢出”情况 ,因此一般情况下都用顺序循环队列的形式

    2.1:顺序循环队列    表现形式任然是数组形式

    常用的操作集合:

    1 public interface queue {
    2     public void append(Object object);        //入队
    3     public Object delete();                    //出队
    4     public Object getFront();                //获得队头点的
    5     public boolean notEmpty();                //判断队列是否为空
    6 }

    具体的顺序队列的实现类:

     1 package com.hone.queue;
     2 
     3 public class SeqQueue implements queue{
     4     
     5     static final int defaultSize=10;
     6     int front;
     7     int rear;
     8     int count;            //元素计数器
     9     int maxsize;        //数据元素最大的个数
    10     Object [] data;        //用于保存队列函数
    11     
    12     public SeqQueue() {
    13         initiate(defaultSize);
    14     }
    15 
    16     private void initiate(int sz) {
    17         maxsize=sz;
    18         front=rear=0;
    19         count=0;
    20         data=new Object[sz];
    21     }
    22 
    23     //向一个队列中开始添加元素    入队列
    24     @Override
    25     public void append(Object object) {
    26         if (count>0&&front==rear) {
    27             System.out.println("队列已满");
    28         }
    29         data[rear]=object;
    30         rear= (rear+1)%maxsize;         //加1取余获得最后队尾的数值
    31         count++;                    //除以maxsize的原因是循环队列
    32     }
    33     
    34     //出队列
    35     @Override
    36     public Object delete() {
    37         if (count==0) {
    38             System.out.println("队列已空");
    39         }
    40         Object temp=data[front];
    41         front=(front+1)%maxsize;    //原来的队头+1后求模得到新的队头位置
    42         count--;
    43         return temp;
    44     }
    45     
    46     //获得队头的位置
    47     @Override
    48     public Object getFront() {
    49         if (count==0) {
    50             System.out.println("队列为空!");
    51         }
    52         return data[front];
    53     }
    54 
    55     @Override
    56     public boolean notEmpty() {
    57         return count!=0;
    58     }
    59     
    60 }

    2.2:链式队列的具体实现形式

    如前面所说:一个结点都必须包含元素+结点

     1 /*
     2  * 整个类使用于封装节点的类
     3  */
     4 public class Node {
     5     Object element;
     6     public Node next;
     7 
     8     // 定义一个构造函数用于初始化头结点
     9     public Node(Node nextval) {
    10         next = nextval;
    11     }
    12 
    13     // 定义一个构造函数用于初始化除了头结点以外的节点
    14     public Node(Object o, Node nextval) {
    15         element = o;
    16         next = nextval;
    17     }
    18 
    19     public Object getElement() {
    20         return element;
    21     }
    22 
    23     public void setElement(Object element) {
    24         this.element = element;
    25     }
    26 
    27     public Node getNext() {
    28         return next;
    29     }
    30 
    31     public void setNext(Node next) {
    32         this.next = next;
    33     }
    34     
    35     //将获得的元素转化为String类型
    36     public String toString(){
    37         return element.toString();
    38     }
    42 }

    链式队列的具体实现:

     1 package com.hone.queue.lin;
     2 
     3 
     4 public class LinQueue implements queue{
     5     Node rear;                        //获得尾结点
     6     Node front;                        //获得尾结点
     7     int count;                        //获得节点的个数
     8     
     9     //定义一个函数用于初始化
    10      private void initiate() {
    11         rear=null;
    12         front= null;
    13         count=0;
    14     }
    15      
    16      public LinQueue() {
    17         initiate();
    18     }
    19      
    20      public  LinQueue(int sz){
    21          initiate();
    22      }
    23     
    24     //用链式的方法入队列
    25     @Override
    26     public void append(Object object) {
    27         Node node=new Node(object, null);
    28         if (rear!=null) {        //如果队尾不为空,则在队尾加上一个新创建的节点
    29             rear.next=node;        //同时将新创建的节点(包含元素和指针)添加到队尾
    30             rear=node;
    31         }
    32         if (front==null) {
    33             front=node;
    34         }
    35         count++;
    36     }
    37     
    38     //用链式的方法出队列
    39     @Override
    40     public Object delete() {
    41         if (count==0)     System.out.println("队列已空");
    42         
    43         Object o=front.getElement();
    44         front=front.next;
    45         count--;
    46         return o;
    47     }
    48     
    49     //获取链式队列的队头位置
    50     @Override
    51     public Object getFront() {
    52         if (count==0) {
    53             System.out.println("队列已空!");
    54         }
    55         return front.getElement();
    56     }
    57     
    58     //判断链式队列是否为空
    59     @Override
    60     public boolean notEmpty() {
    61         return count!=0;
    62     }
    63 }

    2.3:队列同时具有优先级的情况先,将打破了队列  “先入先出” 的原则,优先按照优先级别来处理。

    生活中也会分为轻重缓急。

    那么此时,队列中各个节点,必须包括优先级别+元素

    类似于前面的Node类,这里我们必须加上+ElementPripority类

     1 package com.hone.queue.priority;
     2 
     3 
     4 //定义element元素的属性,包含pripority和element两个属性
     5 public class ElementPripority {
     6     private Object element;
     7     private int pripority;
     8 
     9     // 定义一个构造函数用于初始化element ,pripority
    10     public ElementPripority(Object o, int p) {
    11         element = o;
    12         pripority = p;
    13     }
    14 
    15     public Object getElement() {
    16         return element;
    17     }
    18 
    19     public void setElement(Object element) {
    20         this.element = element;
    21     }
    22 
    23     public int getPripority() {
    24         return pripority;
    25     }
    26 
    27     public void setPripority(int pripority) {
    28         this.pripority = pripority;
    29     }
    30 
    31 }

    具体的实现:

     1 package com.hone.queue.priority;
     2 
     3 import com.hone.queue.queue;
     4 
     5 public class SeqQueue implements queue{
     6     
     7     static final int defaultSize=10;
     8     int front;
     9     int rear;
    10     int count;            //元素计数器
    11     int maxsize;        //数据元素最大的个数
    12     ElementPripority [] data;        //用于保存队列的数组
    13     
    14     public SeqQueue() {
    15         initiate(defaultSize);
    16     }
    17     
    18     public SeqQueue(int sz){
    19         this.initiate(sz);
    20     }
    21 
    22     private void initiate(int sz) {
    23         maxsize=sz;
    24         front=rear=0;
    25         count=0;
    26         data=new ElementPripority[sz];            //创建一个数组并且规定他的大小
    27     }
    28 
    29     //从一个空的队列中开始添加元素    入队列的时候不用管他的pripority属性
    30     @Override
    31     public void append(Object object) {
    32         if (count>0&&front==rear) {
    33             System.out.println("队列已满");
    34         }
    35         data[rear]=(ElementPripority) object; //加入的时候只是在乎他的element属性
    36         rear= (rear+1)%maxsize;                //加1取余获得最后队尾的数值
    37         count++;
    38     }
    39     
    40     //出队列
    41     @Override
    42     public Object delete() {
    43         if (count==0) {
    44             System.out.println("队列已空");
    45         }
    46         //首先要寻找最高优先级别的数,保存在min中
    47         ElementPripority min=data[0];
    48         int minIndex=0;
    49         for (int i = 0; i < count; i++) {
    50             if(data[i].getPripority()<min.getPripority()){
    51                 min=data[i];
    52                 minIndex=i;            //这个方法是在于找到优先级最小的值
    53             }
    54         }
    55         
    56         for (int j = minIndex+1; j < count; j++) {
    57             data[j-1]=data[j];        //因为暂时还没有涉及到除去,只是交换数据,让
    58                             //优先级别最高的排到队头去
    59         }
    60         rear--;
    61         count--;
    62         return min;
    63     }
    64     //获得队头的位置
    65     @Override
    66     public Object getFront() {
    67         if (count==0) {
    68             System.out.println("队列为空!");
    69         }
    70         //首先要寻找最高优先级别的数,保存在min中
    71                 ElementPripority min=data[0];
    72                 int minIndex=0;
    73                 for (int i = 0; i < count; i++) {
    74                     if(data[i].getPripority()<min.getPripority()){
    75                         min=data[i];
    76                         minIndex=i;            //这个方法是在于找到优先级最小的值
    77                     }
    78                 }
    79         return min;
    80     }
    81 
    82     @Override
    83     public boolean notEmpty() {
    84         return count!=0;
    85     }
    86 }

     以上就是队列和堆栈的各种具体实现:

    我们可以用堆栈来模拟回文字符串,或者将进程来模拟计算机中的“进程”。

    利用堆栈+队列  来测试回文字符串

     1 import com.hone.queue.SeqQueue;
     2 import com.hone.stack.SeqStack;
     3 
     4 public class TestOfHuiwen {
     5     public static void main(String[] args) {
     6         String string1="ABCDEDCBA";
     7         String string2="HGJEIEJHG";
     8         
     9         huiwen(string1);
    10         huiwen(string2);
    11     }
    12     
    13     public static void huiwen(String s){
    14         int n=s.length();
    15         SeqStack mystack=new SeqStack();
    16         SeqQueue myqueue=new SeqQueue();
    17         
    18         //先将所有的字符串都加入多对应的队列中去
    19         for (int i = 0; i < n; i++) {
    20             mystack.push(s.substring(i, i+1));
    21             myqueue.append(s.substring(i, i+1));
    22         }
    23         
    24         //从外面取出
    25         while(myqueue.notEmpty()&&mystack.notEmpty()){
    26             if (! myqueue.delete().equals(mystack.pop())) {
    27                 System.out.println(s+" 不是回文字符串!");
    28                 return ;        //如果不是回文字符串则直接回到上面的while循环中
    29             }
    30         }
    31         System.out.println(s+" 是回文字符串!");
    32     }
    33 
    34 }

    这个就是堆栈和队列的一些基本只是。

    当然,这些在java中也已经给我们封装好了,不需要我们具体去写,只需要调用接口即可。

    但是在c ,c++中经常利用与堆栈来进行,多项式的加减啊,用后缀表达式来求取表达式的值。

    作为一个初学者,仍然是一知半解。

  • 相关阅读:
    How to publish ASP.NET application
    Enable(Disable) JavaScript on Browsers(Opera,IE,Firefox,Googlechrome,Safari)
    批处理学习笔记
    [转] Springboot 解决跨域的四种姿势
    HTML+CSS编写规范
    利用CSS3的transform做的动态时钟
    JS特效文字逐个显示
    Asp.Net平台下的图片在线裁剪功能的实现
    CSS3实践之路(一):CSS3之我观
    推荐个通用的多图片上传插件 multiimage。
  • 原文地址:https://www.cnblogs.com/xiaxj/p/6526482.html
Copyright © 2020-2023  润新知