java算法:堆栈ADT及实例
在支持插入和删除数据项集的数据类型中,最重要的数据类型是堆栈。
堆栈:是由两个基本操作构成的ADT,插入(或压入)一个新项,以及删除(或弹出)最近插入的数据项。
例1:堆栈ADT接口
- public interface IIntStack {
- int intStack(int value);
- int empty();
- void push(int value);
- int pop();
- }
例2:中缀法:5*(((9+8)*(4*6))+7),后缀法:5 9 8 + 4 6 * * 7 + *,前缀法:* + 7 * + 9 8 * 4 6 5
后缀计法和相关的压入栈操作应用到计算机中。如:
5 5
9 5 9
8 5 9 8
+ 5 17
4 5 17 4
6 5 17 4 6
* 5 17 24
* 5 408
7 5 408 7
+ 5 415
* 2075
- public class Postfix {
- public static void main(String[] args) {
- char [] a = "598+46**7+*".toCharArray();
- int N = a.length;
- IIntStack s = new IntStackImpl();
- for(int i = 0; i < N; i++){
- if(a[i] == '+'){
- s.push(s.pop() + s.pop());
- }
- if(a[i] == '*'){
- s.push(s.pop() * s.pop());
- }
- if((a[i] >= '0') && (a[i] <= '9')){
- s.push(0);
- }
- while((a[i] >= '0') && (a[i] <= '9')){
- s.push(10 * s.pop() + (a[i++]-'0'));
- }
- }
- System.out.println(s.pop());
- }
- }
例3:中缀到后缀的转换
- public class InfixToPostfix {
- public static void main(String[] args) {
- char [] a = "598+46**7+*".toCharArray();
- int N = a.length;
- IIntStack s = new IntStackImpl();
- for(int i = 0; i < N; i++){
- if(a[i] == ')'){
- System.out.println(s.pop() + " ");
- }
- if((a[i] == '*') || (a[i] == '+')){
- s.push(a[i]);
- }
- if((a[i] >= '0') && (a[i] <= '9')){
- System.out.println(a[i] + " ");
- }
- }
- System.out.println(" ");
- }
- }
栈的ADT实现
主要:数组和链表
例3:堆栈的数组实现
- class IntStack{
- private int[] s;
- private int N;
- IntStack(int maxN){
- s = new int[maxN];
- N = 0;
- }
- boolean isEmpty(){
- return (N == 0);
- }
- void push(int item){
- s[N++] = item;
- }
- int pop(){
- return s[--N];
- }
- }<SPAN></SPAN>
例4:堆栈的链表实现
- class intStack{
- private Node head;
- private class Node{
- int item;
- Node next;
- Node(int item, Node next){
- this.item = item;
- this.next = next;
- }
- }
- intStack(int maxN){
- head = null;
- }
- boolean isEmpty(){
- return (head == null);
- }
- void push(int item){
- head = new Node(item, head);
- }
- int pop(){
- int v = head.item;
- Node t = head.next;
- head = t;
- return v;
- }
- }
客户程序并不关心在数组实现和链表实现中栈的项是否按不同的顺序存放的。实现可自由地使用任何数据结构,只要它能保持抽象堆栈的假象。链表实现能产生栈可以无限增长的假象。而在实际中是不可能的:到达一定时候,当无法满足请求更多内存的要求时,就会抛出异常。
一般实现:定义一个接口,并实现object类型的堆栈,
- Stack s = new Stack(N);
- s.push(a);
- s.push(b);
- a = (Item) s.pop();
- b = (Item) s.pop();
例5:一般堆栈
- class Stack{
- private Object[] s;
- private int N;
- Stack(int maxN){
- s = new Object[maxN];
- N = 0;
- }
- boolean isEmpty(){
- return (M == 0);
- }
- void push(Object item){
- s[N++] = item;
- }
- Object pop(){
- Object t = s[--N];
- s[N] = null;
- return t;
- }
- }
例6:整数栈的适配类
- class IntStack{
- private Stack s;
- intStack(int maxN){
- s = new Stack(maxN);
- }
- boolean isEmpty(){
- return s.isEmpty();
- }
- void push(int item){
- s.push(new Integer(item));
- }
- int pop(){
- return ((Integer)s.pop()).intValue();
- }
- }
创建新的ADT
设计一个新的ADT:开发解决应用问题的客户程序,定义接口,验证ADT是否更容易实现客户程序,再考虑是否合理、效率实现ADT中的操作,如果不能,找到原因进行更改。多次之后,改进的客户程序和ADT,采取策略冻结接口。
例7:等价关系ADT接口,连通性问题:初始化一个抽象数据结构来跟踪给定节点数之间的联系,判断两个给定节点是否连通,并把两个节点连起来,以后就认为它们是连通的。
- class UF{
- UF(int N);
- boolean find(int x; int y);
- void unite(int x; int y);
- }
例8:等价关系ADT的客户
- class Equivalence{
- public static void main(String [] args){
- int p,q, N = 100;
- UF info = new UF(N);
- for(In.init(); !In.empty();){
- p = In.getInt(); q = In.getInt();
- if(!info.find(p,q)){
- info.unite(p,q);
- System.out.println(p + "-" + q);
- }
- }
- }
- }
例9:等价关系ADT实现:加权快速合并实现接口:
- private int [] id, sz;
- private int find(int x){
- while(x != id[x]){
- x = id[x];
- }
- return x;
- }
- UF(int N){
- id = new int[N];
- sz = new int[N];
- for(int i = 0; i < N; i++){
- id[i] = i;
- sz[i] = i;
- }
- }
- boolean find(int p, int q){
- return (find(p) == find(q));
- }
- void unite(int p, int q){
- int i = find(p), j = find(q);
- if(i == j){
- return;
- }
- if(sz[i] < sz[j]){
- id[i] = j; sz[j] += sz[i];
- }else{
- id[j] = i; sz[i] += sz[j];
- }
- }
比较:把解决高层(连通性)问题的任务和解决低层(合并-查找)的问题分开了,从而使我们能独立解决这两个问题;为我们提供了把解决该问题的不同算法和数据结构进行比较的自然方式;通过该接口定义了一个方法来检查软件是否按所期望的操作;为我们提供了一种更新的表示(新数据结构或新算法)而根本不需要改变客户程序的方法;为我们提供了一个能用来构建其他算法的抽象结构。
注意:使用抽象类或接口会产生运行时开销,每个抽象方法的调用需要跟踪表中对方法的一个引用。算法与数据结构经常用于系统中关键的性能部分,不希望以此为代价获得抽象类和接口的灵活性。