1、栈Stack,栈也是一种线性结构,相比数组,栈对应的操作是数组的子集。栈只能从一端添加元素,也只能从同一端取出元素,这一端称为栈顶。栈是一种先进后出的或者后进先出的数据结构,也称为Last In First Out(LIFO)。
2、封装的数组的代码,可以实现增加,修改,删除,查询,动态扩容,缩容,判断是否为空等等方法。
1 package com.company;
2
3
4 /**
5 *
6 */
7 public class Array<E> {
8
9 private E[] data;//定义数组
10 private int size;//数组实际的长度
11
12 /**
13 * 构造函数,传入数组的容量capacity构造Array
14 *
15 * @param capacity 初始化数据的容量长度
16 */
17 public Array(int capacity) {
18 // 使用泛型,可以创建任意类型的数组类型
19 data = (E[]) new Object[capacity];
20 // 初始化数组的实际内容的长度为0
21 size = 0;
22 }
23
24 /**
25 * 无参数的构造函数,默认数组的容量capacity=10
26 */
27 public Array() {
28 // 无参构造函数,指定初始化数组容量长度为0
29 this(10);
30 }
31
32 /**
33 * 获取数组中的元素个数
34 *
35 * @return
36 */
37 public int getSize() {
38 // 获取到数组中的元素个数
39 return size;
40 }
41
42 /**
43 * 获取数组的容量
44 *
45 * @return
46 */
47 public int getCapacity() {
48 // 获取到数组的容量
49 return data.length;
50 }
51
52 /**
53 * 返回数组是否为空
54 *
55 * @return
56 */
57 public boolean isEmpty() {
58 // 判断数组的长度是否为空
59 return size == 0;
60 }
61
62
63 /**
64 * 向所有元素后添加一个新元素
65 *
66 * @param e
67 */
68 public void addLast(E e) {
69 // if (size == data.length) {
70 // throw new IllegalArgumentException("AddLast failed,Array is full......");
71 // } else {
72 // 在数组的末尾添加一个元素
73 // data[size] = e;
74 // 添加元素以后数组长度加一
75 // size++;
76 // }
77
78 // 调用公共的方法,其实就是在数组的实际长度后面添加指定的元素的。
79
80 // 调用添加数组的方法,参数一,传入数组实际的长度,参数二,添加的元素
81 add(size, e);
82 }
83
84 /**
85 * 在第一个位置添加元素,在所有元素前添加一个新元素
86 *
87 * @param e
88 */
89 public void addFirst(E e) {
90 // 在数组的第一个位置添加元素
91 add(0, e);
92 }
93
94
95 /**
96 * 在第index个位置插入一个新元素e
97 *
98 * @param index 在第index个位置
99 * @param e 添加的元素内容
100 */
101 public void add(int index, E e) {
102 // 判断位置index是否小于0或者索引index是否大于数组的实际长度size
103 if (index < 0 || index > size) {
104 throw new IllegalArgumentException("add failed,Require index >= 0 and index <= size.......");
105 }
106
107 // 判断实际长度size是否等于数组的长度
108 if (size == data.length) {
109 // 可以直接抛出异常
110 // throw new IllegalArgumentException("add failed,Array is full......");
111 // 调用数组扩容的方法,扩容的长度为元数组长度的2倍
112 resize(2 * data.length);
113 }
114
115 // 添加元素,就是在最后一个位置,将元素添加进去,即size的位置
116 // 从后向前移动,从后面的元素向后移动
117 // 如果传入的index是size,则初始化的位置是size-1,那么i的值大于等于传入的index(即size的值),i递减
118
119 // int i = size - 1是数组的实际长度的,即最后一个位置的元素
120 // i >= index,是在指定索引位置添加索引
121 // i--是为了将前面的元素向后面移动的。
122 for (int i = size - 1; i >= index; i--) {
123 // 后一个索引位置赋予前一个索引位置的值
124 data[i + 1] = data[i];
125 }
126 // 将元素的内容插入到数组的index索引位置
127 data[index] = e;
128 // 数组的size递增
129 size++;
130 }
131
132 /**
133 * 私用扩容,扩容数组的长度
134 *
135 * @param newCapacity
136 */
137 private void resize(int newCapacity) {
138 // 使用泛型创建对象,使用new Object的方法创建泛型的对象
139 E[] newData = (E[]) new Object[newCapacity];
140 // 循环,将原数组里面的内容放入到新数组里面,新数组的长度为元素组的2倍
141 for (int i = 0; i < size; i++) {
142 // 将原数组的值赋值给新数组的值
143 newData[i] = data[i];
144 }
145 // 将原数组的值指向新数组,此操作,不影响原数组的正常使用
146 data = newData;
147 }
148
149 /**
150 * 获取Index索引位置的元素
151 *
152 * @param index
153 * @return
154 */
155 public E get(int index) {
156 // 如果索引index小于0或者索引的长度大于等于实际长度size,则抛出异常
157 if (index < 0 || index >= size) {
158 throw new IllegalArgumentException("add failed,Index is illegal......");
159 }
160 // 返回指定索引位置的数组元素
161 return data[index];
162 }
163
164 /**
165 * 获取到动态数组的第一个元素
166 *
167 * @return
168 */
169 public E getFirst() {
170 return get(0);
171 }
172
173 /**
174 * 获取到数组的最后一个元素
175 *
176 * @return
177 */
178 public E getLast() {
179 // 调用获取元素的方法
180 // 避免使用return data[size - 1],可能会出现size=0的情况
181 return get(size - 1);
182 }
183
184 /**
185 * 修改index索引位置的元素e
186 *
187 * @param index
188 */
189 public void set(int index, E e) {
190 // 如果索引index小于0或者索引的长度大于等于实际长度size,则抛出异常
191 if (index < 0 || index >= size) {
192 throw new IllegalArgumentException("add failed,Index is illegal......");
193 }
194 // 则将元素放入到数组的索引index位置
195 data[index] = e;
196 }
197
198
199 /**
200 * @return
201 */
202 @Override
203 public String toString() {
204 // 封装数组遍历的内容
205 StringBuilder sb = new StringBuilder();
206 sb.append(String.format("Array : size = %d,capacity = %d\n", size, data.length));
207 sb.append('[');
208 for (int i = 0; i < size; i++) {
209 sb.append(data[i]);
210 if (i != size - 1) {
211 sb.append(", ");
212 }
213 }
214 sb.append(']');
215 return sb.toString();
216 }
217
218 /**
219 * 查找数据中是否包含元素e
220 *
221 * @param e
222 * @return
223 */
224 public boolean contains(E e) {
225 // 查看是否包含元素,进行遍历
226 for (int i = 0; i < size; i++) {
227 // 如果数组元素等于传入的元素e
228 if (data[i].equals(e)) {
229 // 返回true
230 return true;
231 }
232 }
233 return false;
234 }
235
236 /**
237 * 查找数组中元素e所在的索引,如果不存在元素e,则返回-1
238 *
239 * @param e
240 * @return
241 */
242 public int find(E e) {
243 // 查看是否包含元素,进行遍历
244 for (int i = 0; i < size; i++) {
245 // 如果数组元素等于传入的元素e
246 if (data[i].equals(e)) {
247 // 返回该索引位置的索引
248 return i;
249 }
250 }
251 return -1;
252 }
253
254 /**
255 * 从数组中删除index位置的元素,返回删除的元素
256 *
257 * @param index 此参数是索引参数
258 * @return
259 */
260 public E remove(int index) {
261 // 如果索引位置小于等于0或者索引位置大于等于数组的实际长度size
262 if (index < 0 || index >= size) {
263 throw new IllegalArgumentException("remove failed,Index is illegal......");
264 }
265
266 // 返回删除的元素,先获取到要删除的元素
267 E result = data[index];
268 // System.out.println(result);
269
270 // 初始化值是要删除索引的位置加1,且i的值小于实际size的大小,i递减
271
272 // int i = index + 1,传入进去的删除索引位置的元素
273 // i < size,i小于数组的实际长度
274 // i++,i递增
275 for (int i = index + 1; i < size; i++) {
276 // 将数组元素的值赋值被删除元素的位置上面
277 // 即将数组元素向前移动,即第i位置的索引的数据移动到第i-1位置索引的数据
278 data[i - 1] = data[i];
279 }
280 // 删除元素以后,数组长度size递减1
281 size--;
282 // 将不可访问的位置置空
283 data[size] = null;
284
285 // 避免出现复杂度震荡
286 // 删除数组长度,缩小容量
287 // data.length / 2 != 0,避免出现创建数组长度为0的数组
288 if (size == data.length / 4 && data.length / 2 != 0) {
289 // 缩容数组的长度
290 resize(data.length / 2);
291 }
292 return result;
293 }
294
295 /**
296 * 删除数组的第一个元素的值
297 * <p>
298 * 从删除中删除第一个元素,返回删除的元素
299 *
300 * @return
301 */
302 public E removeFirst() {
303 // 删除数组的第一个位置的元素
304 return remove(0);
305 }
306
307 /**
308 * 从数组中删除最后一个元素,返回删除的元素。
309 *
310 * @return
311 */
312 public E removeLast() {
313 // 删除数组最后一个位置的元素
314 return remove(size - 1);
315 }
316
317 /**
318 * 从数组中删除元素e
319 *
320 * @param e
321 */
322 public void removeElement(E e) {
323 // 查看数组里面是否有该元素
324 int index = find(e);
325 // 如果查找到存在该元素
326 if (index != -1) {
327 // 调用删除数组元素的方法
328 remove(index);
329 }
330 }
331
332 public static void main(String[] args) {
333 // 数组添加元素
334 Array<Integer> array = new Array<>(20);
335 for (int i = 0; i < 10; i++) {
336 array.addLast(i);
337 }
338
339 System.out.println(array.toString());
340
341 // 在指定位置添加元素
342 array.add(1, 110);
343 System.out.println(array.toString());
344
345 // 在第一个位置添加元素
346 array.addFirst(-1);
347 System.out.println(array.toString());
348
349 // 修改index索引位置的元素e
350 array.set(1, 120);
351 System.out.println(array.toString());
352
353 // 是否包含某个元素
354 boolean contains = array.contains(9);
355 System.out.println(contains);
356
357 // 删除指定索引位置的元素
358 array.remove(2);
359 System.out.println(array);
360
361 // 删除第一个索引位置的元素
362 array.removeFirst();
363 System.out.println(array);
364
365 // 删除最后一个位置的元素
366 array.removeLast();
367 System.out.println(array);
368
369 // 从数组中删除元素e
370 array.removeElement(110);
371 System.out.println(array);
372 }
373
374 }
3、使用泛型,可以接受任何数据类型的。声明栈的接口。
1 package com.stack;
2
3 /**
4 * @param <E> 使用泛型,可以接受任何数据类型的
5 */
6 public interface Stack<E> {
7
8 /**
9 * 获取到栈里面的大小
10 *
11 * @return
12 */
13 public int getSize();
14
15 /**
16 * 判断栈是否为空
17 *
18 * @return
19 */
20 public boolean isEmpty();
21
22 /**
23 * 向栈中添加一个元素,即入栈
24 *
25 * @param e
26 */
27 public void push(E e);
28
29 /**
30 * 从栈中取出栈顶的元素,即出栈
31 *
32 * @return
33 */
34 public E pop();
35
36 /**
37 * 查看栈顶的元素
38 *
39 * @return
40 */
41 public E peek();
42
43 }
创建实现Stack自定义接口栈的类,ArrayStack栈,结合创建的Array<E>动态数组来实现栈的入栈,出栈,查看栈顶元素,判断栈是否为空等等操作。
1 package com.stack;
2
3 import com.company.Array;
4
5 /**
6 * 时间复杂度都是O(1)的
7 * <p>
8 * <p>
9 * 1)、void push(E),时间复杂度0(1),均摊时间复杂度。
10 * 2)、E pop(),时间复杂度0(1),均摊时间复杂度。
11 * 3)、E peek(),时间复杂度0(1)。
12 * 4)、int getSize(),时间复杂度0(1)。
13 * 5)、boolean isEmpty(),时间复杂度0(1)。
14 * <p>
15 * <p>
16 * 栈的应用。
17 * 1)、undo操作,编辑器。
18 * 2)、系统调用栈-操作系统。
19 * 3)、括号匹配-编辑器。
20 *
21 * @param <E>
22 */
23 public class ArrayStack<E> implements Stack<E> {
24
25 public Array<E> array;
26
27 // Fn + Alt + Insert快捷键弹出构造函数
28
29 /**
30 * @param array
31 */
32 public ArrayStack(Array<E> array) {
33 this.array = array;
34 }
35
36 /**
37 * @param capacity 动态数组的容量大小
38 */
39 public ArrayStack(int capacity) {
40 // 初始化动态数组的初始化大小
41 array = new Array<>(capacity);
42 }
43
44 /**
45 * 无参的栈构造函数,创建一个默认容量大小的动态数组
46 */
47 public ArrayStack() {
48 array = new Array<>();
49 }
50
51 @Override
52 public int getSize() {
53 // 直接返回动态数组的大小即可
54 return array.getSize();
55 }
56
57 @Override
58 public boolean isEmpty() {
59 // // 调用动态数组的是否为空,如果为空,则返回为空
60 // boolean empty = array.isEmpty();
61 // if (empty) {
62 // return true;
63 // }
64 // return false;
65 return array.isEmpty();
66 }
67
68 @Override
69 public void push(E e) {
70 // 调用向动态数组的末尾添加元素即可
71 array.addLast(e);
72 }
73
74 @Override
75 public E pop() {
76 // 从栈顶中取出元素
77 E e = array.removeLast();
78 // 并将从栈顶中获取的元素取出,即移除栈顶中的元素
79 return e;
80 }
81
82 @Override
83 public E peek() {
84 // 获取栈顶的元素
85 return array.getLast();
86 }
87
88 /**
89 * 判断栈的容量大小
90 *
91 * @return
92 */
93 public int getCapacity() {
94 // 直接调用获取数组的容量大小
95 return array.getCapacity();
96 }
97
98 /**
99 * 代码格式化快捷键Ctrl + Alt + l
100 * <p>
101 * 弹出构造方法的快捷键
102 *
103 * @return
104 */
105 @Override
106 public String toString() {
107 StringBuffer sb = new StringBuffer();
108 sb.append("Stack:");
109 sb.append('[');
110 for (int i = 0; i < array.getSize(); i++) {
111 sb.append(array.get(i));
112 if (i != array.getSize() - 1) {
113 sb.append(", ");
114 }
115 }
116 sb.append("] top");
117 return sb.toString();
118 }
119
120 public static void main(String[] args) {
121 // 声明一个ArrayStack的对象
122 ArrayStack<Integer> arrayStack = new ArrayStack<>(20);
123 for (int i = 0; i < 10; i++) {
124 // 入栈操作
125 arrayStack.push(i);
126 System.out.println(arrayStack.toString());
127 }
128
129 // 出栈操作
130 arrayStack.pop();
131 System.out.println("出栈操作: " + arrayStack.toString());
132
133 // 查看栈的容量
134 int capacity = arrayStack.getCapacity();
135 System.out.println("查看栈的容量: " + capacity);
136
137 // 获取到栈的大小
138 int size = arrayStack.getSize();
139 System.out.println("获取到栈的大小: " + size);
140
141 // 获取到栈顶的元素内容
142 Integer peek = arrayStack.peek();
143 System.out.println("获取到栈顶的元素内容: " + peek);
144 }
145
146 }
4、leetcode的一道算法题,结合栈实现的。题目如下所示:
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。有效字符串需满足:
1、左括号必须用相同类型的右括号闭合。
2、左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
1 package com.leetcode;
2
3 import java.util.Stack;
4
5 /**
6 * 栈顶元素反映了在嵌套的层次关系中,最近的需要匹配的元素。
7 */
8 public class Solution {
9
10 public boolean isValid(String s) {
11 // 创建一个栈Stack对象
12 Stack<Character> stack = new Stack<>();
13 // 遍历字符串
14 for (int i = 0; i < s.length(); i++) {
15 // 获取到每一个字符串的字符
16 char c = s.charAt(i);
17 // 判断,如果字符是左侧符号类型(、{、[这三类字符串,就将这三类字符串入栈操作
18 if (c == '(' || c == '{' || c == '[') {
19 // 如果是这三类字符,就进行入栈操作
20 stack.push(c);
21 } else {
22 // 否则,该字符是右侧的括号类型)、}、]
23 // 判断栈顶的字符和该字符是否匹配。
24
25 // 首先判断栈是否为空,如果为空,直接返回false
26 if (stack.isEmpty()) {
27 return false;
28 } else {
29 // 获取到栈顶的元素,开始进行判断栈顶的元素和该字符是否匹配
30 // stack.pop()方法调用就是将栈顶元素出栈的哦!,切记
31 char topChar = stack.pop();
32
33 // 如果字符是右侧的)字符,并且栈顶的元素不等于左侧的(符号
34 if (c == ')' && topChar != '(') {
35 return false;
36 }
37 // 如果字符是右侧的]字符,并且栈顶的元素不等于左侧的[符号
38 if (c == ']' && topChar != '[') {
39 return false;
40 }
41 // 如果字符是右侧的}字符,并且栈顶的元素不等于左侧的{符号
42 if (c == '}' && topChar != '{') {
43 return false;
44 }
45
46 }
47 }
48
49 }
50
51 // 最后判断栈是否为空,如果不为空,则直接返回true,否则返回false
52 return stack.isEmpty();
53 }
54
55 public static void main(String[] args) {
56 // 创建一个Solution对象
57 Solution solution = new Solution();
58 // 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
59 //
60 // 有效字符串需满足:
61 //
62 // 1、左括号必须用相同类型的右括号闭合。
63 // 2、左括号必须以正确的顺序闭合。
64 //
65 // 注意空字符串可被认为是有效字符串。
66 // String str = "()[]{}";
67 String str = "([{}])";
68 boolean valid = solution.isValid(str);
69 System.out.println(valid);
70 }
71
72 }
作者:别先生
博客园:https://www.cnblogs.com/biehongli/
如果您想及时得到个人撰写文章以及著作的消息推送,可以扫描上方二维码,关注个人公众号哦。
来源:https://www.cnblogs.com/biehongli/p/12368190.html