数据结构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++中经常利用与堆栈来进行,多项式的加减啊,用后缀表达式来求取表达式的值。

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

原文地址:https://www.cnblogs.com/xiaxj/p/6526482.html