前言:之前介绍了线性表,今天来介绍一下堆栈/队列。
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++中经常利用与堆栈来进行,多项式的加减啊,用后缀表达式来求取表达式的值。
作为一个初学者,仍然是一知半解。