数据结构-栈与队列

  1. 相比于数组这种存储数据的数据,栈(Stock)和队列(Queue)主要作用是在程序中作为构思算法的辅助工具,是一种程序员开发过程中的便利工具。Stock和Queue具有访问受限以及更加抽象的特征。

一、栈

栈只允许访问最后一个插入的元素,即栈是先进后出(FILO)的一种数据结构。栈主要提供的算法包括push,pop和peek。其中push是插入一个元素,pop是弹出最近添加的一个元素,peek是返回最近添加的一个元素。

栈的底层实现可以是数组,也可以是链表,这里采用数组实现一个栈,代码如下:

 1 public class Stock1<T> {
 2     private static final int EMPTY_TOP = -1;
 3     private int maxSize;
 4     private Object[] stockArray;
 5     private int top;
 6
 7     public Stock1() {
 8         this(16);
 9     }
10
11     public Stock1(int initialCapacity) {
12         if (initialCapacity < 0) {
13             throw new IllegalArgumentException("The initialCapacity value must > 0, this value is:" + initialCapacity);
14         }
15
16         this.maxSize = initialCapacity;
17         this.top = EMPTY_TOP;
18         this.stockArray = new Object[this.maxSize];
19     }
20
21     public void push(T value) {
22         this.checkIndex(this.top + 1);
23         this.stockArray[++this.top] = value;
24     }
25
26     @SuppressWarnings("unchecked")
27     public T pop() {
28         this.checkIndex(this.top);
29         return ((T) this.stockArray[this.top--]);
30     }
31
32     @SuppressWarnings("unchecked")
33     public T peek() {
34         this.checkIndex(this.top);
35         return (T) this.stockArray[this.top];
36     }
37
38     public boolean isEmpty() {
39         return this.top == EMPTY_TOP;
40     }
41
42     public boolean isFull() {
43         return this.top == this.maxSize - 1;
44     }
45
46     public int size() {
47         return this.top + 1;
48     }
49
50     private void checkIndex(int index) {
51         if (index < 0 || index >= maxSize) {
52             throw new IllegalArgumentException("The index is error, index:=" + index + ", the max index is:" + (maxSize - 1));
53         }
54     }
55
56     @Override
57     public String toString() {
58         StringBuffer sb = new StringBuffer(this.maxSize);
59         for (int i = this.top; i >= 0; i--) {
60             sb.append(this.stockArray[i]).append(",");
61         }
62         return "[" + sb.substring(0, Math.max(sb.length() - 1, 0)) + "]";
63     }
64 }

二、队列

队列和栈一样,也只允许访问一个元素,但是这个元素是最早插入的,即队列是一个先进先出(FIFO)的数据结构。队列主要提供的算法包括insert,remove和peek。其中insert是在队列的尾部插入一个元素;remove是在队列的头部删除一个元素,并返回;peek是返回队列头部的元素的值。

队列的底层实现和栈一样,可以是数组或者是链表,代码如下:

 1 public class Queue1<T extends Comparable<T>> {
 2     private static int EMPTY_INDEX = 0;
 3     protected final int maxSize;
 4     protected final Comparable<T>[] queueArray;
 5     protected int head;
 6     protected int tail;
 7     protected int size;
 8
 9     @SuppressWarnings("unchecked")
10     public Queue1(int initialCapacity) {
11         if (initialCapacity < 0) {
12             throw new IllegalArgumentException("The initialCapacity value must > 0, this value is:" + initialCapacity);
13         }
14
15         this.maxSize = initialCapacity;
16         this.queueArray = (Comparable<T>[]) Array.newInstance(Comparable.class, this.maxSize);
17         this.head = EMPTY_INDEX;
18         this.tail = EMPTY_INDEX;
19         this.size = 0;
20     }
21
22     public void push(T value) {
23         if (isFull()) {
24             throw new IllegalArgumentException("The queue is full, can‘t push value to this queue.");
25         } else {
26             this.size++;
27             this.queueArray[(this.tail++) % this.maxSize] = value;
28         }
29     }
30
31     @SuppressWarnings("unchecked")
32     public T pop() {
33         if (isEmpty()) {
34             throw new IllegalArgumentException("The queue is empty, can‘t pop value.");
35         } else {
36             this.size--;
37             return (T) this.queueArray[(this.head++) % this.maxSize];
38         }
39     }
40
41     @SuppressWarnings("unchecked")
42     public T peek() {
43         if (isEmpty()) {
44             throw new IllegalArgumentException("The queue is empty, can‘t peek value.");
45         } else {
46             return (T) this.queueArray[this.head % this.maxSize];
47         }
48     }
49
50     public boolean isEmpty() {
51         return this.size == 0;
52     }
53
54     public boolean isFull() {
55         return this.size == this.maxSize;
56     }
57
58     public int size() {
59         return this.size;
60     }
61 }

这段代码中我将insert方法换成了push方法,remove方法换成了pop方法。

三、优先级队列

优先级队列和普通队列类似,区别在于在remove元素的时候,返回的元素值是按照某种顺序来定义的。实现优先级队列有两种方式:

第一种,在插入元素的时候,按顺排列。即每次插入的时候,都会将要插入的元素插入到对应位置,并移动其他元素。此时插入的时间复杂度是O(n2),但是这样删除的代码和普通队列一样。

第二中,在插入元素的时候,直接将元素填充到队列尾部,但是在删除的时候,search全部数据,选择出要删除的数据出来。此时插入时间复杂度O(1),删除复杂度为O(n2)。

我们采用第一种方式来实现一个队列,针对插入数据慢的问题,我们可以采用堆来解决这个问题,以后再说。代码如下:

第一种代码是继承普通队列,只修改push方法:

 1 public class PriorityQueue1<T extends Comparable<T>> extends Queue1<T> {
 2     public PriorityQueue1(int initialCapacity) {
 3         super(initialCapacity);
 4     }
 5
 6     public void push(T value) {
 7         if (isFull()) {
 8             throw new IllegalArgumentException("This queue is full");
 9         } else {
10             int index = super.head;
11             for (int i = 0; i < super.size; i++) {
12                 int compareResult = super.queueArray[index++ % super.maxSize].compareTo(value);
13                 if (compareResult >= 0) {
14                     index--;
15                     break;
16                 }
17             }
18
19             for (int i = super.tail; i > index; i--) {
20                 super.queueArray[i % super.maxSize] = super.queueArray[(i - 1) % super.maxSize];
21             }
22
23             super.queueArray[index] = value;
24             super.tail++;
25             super.size++;
26         }
27     }
28 }

第二种是不继承普通队列,自己实现:

 1 public class PriorityQueue2<T extends Comparable<T>> {
 2     protected final int maxSize;
 3     protected int nItems;
 4     protected Comparable<T>[] basicArray;
 5
 6     @SuppressWarnings("unchecked")
 7     public PriorityQueue2(int initialCapacity) {
 8         if (initialCapacity < 0) {
 9             throw new IllegalArgumentException("The initialCapacity value must > 0, this value is:" + initialCapacity);
10         }
11
12         this.maxSize = initialCapacity;
13         this.basicArray = (Comparable<T>[]) Array.newInstance(Comparable.class, this.maxSize);
14         this.nItems = 0;
15     }
16
17     public boolean isEmpty() {
18         return this.nItems == 0;
19     }
20
21     public boolean isFull() {
22         return this.nItems == this.maxSize;
23     }
24
25     public int size() {
26         return this.nItems;
27     }
28
29     public void push(T value) {
30         if (this.isFull()) {
31             throw new IllegalArgumentException("This queue is full, can‘t push value.");
32         } else {
33             int index = 0;
34             for (; index < this.nItems; index++) {
35                 if (this.basicArray[index].compareTo(value) <= 0) {
36                     break;
37                 }
38             }
39
40             for (int j = this.nItems; j > index; j--) {
41                 this.basicArray[j] = this.basicArray[j - 1];
42             }
43
44             this.basicArray[index] = value;
45             this.nItems++;
46         }
47     }
48
49     @SuppressWarnings("unchecked")
50     public T pop() {
51         if (this.isEmpty()) {
52             throw new IllegalArgumentException("This queue is empty, can‘t pop value.");
53         } else {
54             return (T) this.basicArray[--nItems];
55         }
56     }
57
58     @SuppressWarnings("unchecked")
59     public T peek() {
60         if (this.isEmpty()) {
61             throw new IllegalArgumentException("This queue is empty, can‘t peek value.");
62         } else {
63             return (T) this.basicArray[this.nItems - 1];
64         }
65     }
66 }

四、其他代码

1.解析表达式,将中缀表达式转换成后缀表达式

  1 public class InToPost {
  2     private Stock1<Character> stock;
  3     private Queue1<String> queue;
  4     private String input;
  5     private StringBuffer sb;
  6
  7     public InToPost(String input) {
  8         if (input != null && input.length() != 0) {
  9             this.input = input.trim();
 10         } else {
 11             this.input = "";
 12         }
 13
 14         this.stock = new Stock1<>(this.input.length());
 15         this.sb = new StringBuffer(this.input.length());
 16         this.queue = new Queue1<>(this.input.length());
 17     }
 18
 19     public String getInput() {
 20         return input;
 21     }
 22
 23     public String getOutput() {
 24         return this.sb.toString();
 25     }
 26
 27     public String doTranshi() {
 28         StringBuffer tmp = new StringBuffer();
 29
 30         for (int j = 0; j < this.input.length(); j++) {
 31             char ch = this.input.charAt(j);
 32             switch (ch) {
 33             case ‘+‘:
 34             case ‘-‘:
 35                 pushValueToQueue(tmp.toString());
 36                 sb.append(tmp.toString());
 37                 tmp = new StringBuffer();
 38                 gotPot(ch, 1);
 39                 break;
 40
 41             case ‘*‘:
 42             case ‘/‘:
 43                 pushValueToQueue(tmp.toString());
 44                 sb.append(tmp.toString());
 45                 tmp = new StringBuffer();
 46                 gotPot(ch, 2);
 47                 break;
 48
 49             case ‘(‘:
 50                 this.stock.push(ch);
 51                 break;
 52
 53             case ‘)‘:
 54                 pushValueToQueue(tmp.toString());
 55                 sb.append(tmp.toString());
 56                 tmp = new StringBuffer();
 57                 while (!this.stock.isEmpty()) {
 58                     char chx = this.stock.pop();
 59                     if (chx == ‘(‘) {
 60                         break;
 61                     } else {
 62                         sb.append(chx);
 63                         pushValueToQueue(String.valueOf(chx));
 64                     }
 65                 }
 66                 break;
 67
 68             default:
 69                 tmp.append(ch);
 70                 break;
 71             }
 72         }
 73
 74         pushValueToQueue(tmp.toString());
 75         sb.append(tmp.toString());
 76
 77         while (!this.stock.isEmpty()) {
 78             char ch = this.stock.pop();
 79             this.sb.append(ch);
 80             pushValueToQueue(String.valueOf(ch));
 81         }
 82
 83         return this.getOutput();
 84     }
 85
 86     private void gotPot(char ch, int prec) {
 87         while (!this.stock.isEmpty()) {
 88             char chx = this.stock.pop();
 89             if (chx == ‘(‘) {
 90                 this.stock.push(chx);
 91                 break;
 92             } else {
 93                 int prec2 = 2;
 94                 if (chx == ‘+‘ || chx == ‘-‘) {
 95                     prec2 = 1;
 96                 }
 97                 if (prec2 >= prec) {
 98                     sb.append(chx);
 99                     pushValueToQueue(String.valueOf(chx));
100                 } else {
101                     this.stock.push(chx);
102                     break;
103                 }
104             }
105         }
106         this.stock.push(ch);
107     }
108
109     private void pushValueToQueue(String value) {
110         if (value == null || value.trim().length() == 0) {
111             return;
112         }
113         this.queue.push(value.trim());
114     }
115
116     public Queue1<String> getQueue() {
117         return this.queue;
118     }
119 }
120
121 class InToPostUtil {
122     public static String doTranshi(String line) {
123         return new InToPost(line).doTranshi();
124     }
125 }
126
127 class InToPostApp {
128     public static void main(String[] args) {
129         System.out.println(InToPostUtil.doTranshi(null));
130         System.out.println(InToPostUtil.doTranshi(""));
131         System.out.println(InToPostUtil.doTranshi("     "));
132         System.out.println(InToPostUtil.doTranshi("a*b+c"));
133         System.out.println(InToPostUtil.doTranshi("a*(b+c)"));
134         System.out.println(InToPostUtil.doTranshi("a*(b+c*d)"));
135         System.out.println(InToPostUtil.doTranshi("a*(b+c*d/(e-f*g))"));
136     }
137 }

2.计算后缀表达式的值

 1 package com.augmentum.gby.ds;
 2
 3 public class ParsePost {
 4     private String line;
 5     private InToPost inToPost;
 6
 7     public ParsePost(String line) {
 8         this.line = line;
 9         this.inToPost = new InToPost(this.line);
10     }
11
12     public double doParse() {
13         String reline = this.inToPost.doTranshi();
14         if (reline == null || reline.length() == 0) {
15             throw new IllegalArgumentException("The input line value is empty. can‘t calc those value.");
16         } else {
17             Stock1<Double> stock = new Stock1<>(reline.length());
18             Queue1<String> queue = this.inToPost.getQueue();
19             while (!queue.isEmpty()) {
20                 String value = queue.pop();
21                 if ("+".equals(value) || "-".equals(value) || "*".equals(value) || "/".equals(value)) {
22                     double num1 = stock.pop();
23                     double num2 = stock.pop();
24                     switch (value.charAt(0)) {
25                     case ‘+‘:
26                         stock.push(num1 + num2);
27                         break;
28                     case ‘-‘:
29                         stock.push(num2 - num1);
30                         break;
31                     case ‘*‘:
32                         stock.push(num2 * num1);
33                         break;
34                     case ‘/‘:
35                         stock.push(num2 / num1);
36                         break;
37                     }
38                 } else {
39                     stock.push(Double.valueOf(value));
40                 }
41             }
42             return stock.pop();
43         }
44     }
45 }
46
47 class ParsePostUtil {
48     public static double doParse(String line) {
49         return new ParsePost(line).doParse();
50     }
51 }
52
53 class ParsePostApp {
54     public static void main(String[] args) {
55         System.out.println(InToPostUtil.doTranshi("2*((3+4)*5+5)"));
56         System.out.println(InToPostUtil.doTranshi("2*3+4") + "; The result is:" + ParsePostUtil.doParse("2*3+4"));
57         System.out.println(InToPostUtil.doTranshi("2*(3+4)") + "; The result is:" + ParsePostUtil.doParse("2*(3+4)"));
58         System.out.println(InToPostUtil.doTranshi("2*(3+4*5)") + "; The result is:" + ParsePostUtil.doParse("2*(3+4*5)"));
59         System.out.println(InToPostUtil.doTranshi("2*3+4*5") + "; The result is:" + ParsePostUtil.doParse("2*3+4*5"));
60         System.out.println(InToPostUtil.doTranshi("2*((3+4)*5+5)") + "; The result is:" + ParsePostUtil.doParse("2*((3+4)*5+5)"));
61         System.out.println(InToPostUtil.doTranshi("2*((3+4)*5+9)") + "; The result is:" + ParsePostUtil.doParse("2*((3+4)*5+9)"));
62         System.out.println(InToPostUtil.doTranshi("20*3+4") + "; The result is:" + ParsePostUtil.doParse("20*3+4"));
63         System.out.println(InToPostUtil.doTranshi("20.5*4+4") + "; The result is:" + ParsePostUtil.doParse("20.5*4+4"));
64     }
65 }

时间: 2024-09-29 01:25:00

数据结构-栈与队列的相关文章

C数据结构-栈和队列,括号匹配举例

1.栈和队列是两种特殊的线性表 运算操作被限定只能在表的一端或两端插入,删除元素,故也称它们为限定的线性表结构 2.栈的基本运算 1).Stackinit(&s) 构造一个空栈 2).Stackempty(s) 判断s是否为空栈,当s为空栈时,函数返回值1 否则 0 3).Push(&s,x)  在栈s 的顶部插入元素x,简称将x入 栈 4).Pop(&s,&x) 在栈s 中删除顶元并将其值保存在x单元中返回,简称将x出栈 5)Gettop(s,&x)  读s栈中的

数据结构——栈和队列相关算法实现

数据结构栈和队列的基本算法实现 限定性线性表--栈 栈的定义 栈作为一种限定性的线性表,是将线性表的插入和删除操作限制为仅在表的一端进行. 基本算法演示 /* 栈的常见操作: 1.初始化栈 2.元素进栈 3.元素出栈 4.栈的遍历 5.判断栈是否为空栈 6.清空整个栈 */ # include <stdio.h> # include <stdlib.h> typedef struct Node { int date; struct Node * pNext; }NODE,* PNO

C#数据结构—栈和队列

一:栈 栈和队列也是线性结构,线性表.栈和队列这三种数据结构的数据元素以及数据元素间的逻辑关系完全相同,差别是线性表的操作不受限制,而栈和队列的操作受到限制.栈的操作只能在表的一端进行,队列的插入操作在表的一端进行而其它操作在表的另一端进行,所以,把栈和队列称为操作受限的线性表. 1:栈的定义及基本运算 栈(Stack)是操作限定在表的尾端进行的线性表.表尾由于要进行插入.删除等操作,所以,它具有特殊的含义,把表尾称为栈顶(Top),另一端是固定的,叫栈底(Bottom).当栈中没有数据元素时叫

c数据结构 -- 栈与队列

栈和队列 ·栈和队列是两种常用的.重要的数据结构 ·栈和队列是限定插入和删除只能在表的“端点”进行的线性表 栈 只能在队尾插入,只能在队尾删除 -- 后进后出 表尾称为栈顶:表头称为栈底 插入元素到栈顶(即表尾)的操作,称为入栈 从栈顶删除最后一个元素的操作,称为出栈 注意:函数调用的流程就是入栈和出栈的实现,遵循后调用的先返回 队列 只能在队尾插入,只能在对队头删除 -- 先进先出 顺序栈的实现: #include <stdio.h> #include <stdlib.h> #d

数据结构-栈、队列和链表

一.栈stack 是后进先出的数据结构 栈顶指针指的始终是栈最上方元素的一个标记,即放在最上面的元素.栈顶元素为空时令top为-1. 在使用pop()函数和top()函数时,需要使用empty()判断栈是否为空. 在STL中stack容器来编写代码,STL定义stack的复杂度是O(1). 常见函数: clear() size() empty() push() pop() top() 二.队列queue 是一种先进先出的数据结构 需要一个队首指针front来指向队首元素的前一个位置,而使用一个队

数据结构-栈和队列

栈和队列都是线性表,所以满足-只有一个节点没有前继,只有后继,只有一个节点只有后继没有前继,其他的节点只有一个前继只有一个后继. 栈的定义是先进后出,最典型的例子就是弹夹,最先进去的反而是最后射出来的,在实际的软件开发中会进经常的遇到这种类型的线性表,我们成为LIFO(Last in First out).可以把栈想象成是只有一个出口的容器,最先放进去的东西只能够等其上面的东西呗拿走之后才能够拿出来. 队列则是另外的一种线性表,队列在我们生活中就更常见了,比如排队啊什么的,队列讲的是先进先出,在

JavaScript数据结构——栈和队列

栈:后进先出(LIFO)的有序集合 队列:先进先出(FIFO)的有序集合 ------------------------------------------------------------------------------------------------------ 栈方法声明: 首先,采用数组来保存栈里的元素. 序号 方法 说明 1 push ( element(s) ) 添加一个(或几个)新元素到栈顶 2 pop ( ) 移除栈顶的元素,同时返回被移除的元素 3 peek ( )

数据结构——栈与队列

题目: 1.编写函数,采用链式存储实现栈的初始化.入栈.出栈操作 2.编写函数,采用顺序存储实现栈的初始化.入栈.出栈操作 3.编写函数,采用链式存储实现队列的初始化.入队.出队操作 4.编写函数,采用顺序存储实现队列的初始化.入队.出队操作 5.编写一个主函数,在主函数中设计一个简单的菜单,分别调试上述算法 题目分析: 1.顺序栈的类型定义 #define MAX 100  //栈的最大值 typedef struct {     ElemType *base;     int top; } 

考研数据结构-栈和队列

栈 栈是一种只能在一端进行插入或删除操作的线性表. 线性表:栈的逻辑结构属于线性表,只不过在操作上加了一些约束. 一端:可以插入或者删除元素的一端叫栈顶,另一端叫栈底. 顺序栈 1 int stack[maxSize]; 2 int top = -1; 3 4 //元素入栈 5 stack[++top] = x; 6 7 //元素出栈 8 x = stack[top--]; 链栈 1 LNode *head = (LNode*)malloc(sizeof(LNode)); 2 head→next