第 14 天: 栈
14.1 push 和 pop 均只能在栈顶操作.
14.2 没有循环, 时间复杂度为 O ( 1 ) O(1)O(1).
第 15 天: 栈的应用(括号匹配)
任务描述: 检查一个字符串的括号是否匹配. 所谓匹配, 是指每个左括号有相应的一个右括号与之对应, 且左括号不可以出现在右括号右边. 可以修改测试字符串, 检查不同情况下的运行.
15.1 仅在昨天的代码基础上增加了一个 bracketMatching 方法, 以及 main 中的相应调拭语句.
15.2 操作系统的核心数据结构. 对于计算机而言, 如何降低时间、空间复杂度才是王道.
15.3 除了关注的括号, 其它字符不起任何作用.
15.4 一旦发现不匹配, 就直接返回, 不用罗嗦.
package linear_data_structure;
public class CharStack {
//The depth.
public static final int MAX_DEPTH = 10;
//The actual depth.
int depth;
//The data
char[] data;
//Construct an empty char stack.
public CharStack() {
depth = 0;
data = new char[MAX_DEPTH];
}
//Overrides the method claimed in Object, the superclass of any class.
public String toString() {
String resultString = "";
for (int i = 0; i < depth; i++) {
resultString += data[i];
}
return resultString;
}
//push
//@param paraChar The given char.
//@return Success or not.
public boolean push(char parachar) {
if (depth == MAX_DEPTH) {
System.out.println("Stack full.");
return false;
}
data[depth] = parachar;
depth++;
return true;
}
//pop
public char pop() {
if (depth == 0) {
System.out.println("Nothing to pop.");
return '\0';
}
depth--;
return data[depth];
}
public static boolean bracketMatching(String paraString) {
//Step 1. Initialize the stack through pushing a '#' as a buttom
CharStack tempStack = new CharStack();
tempStack.push('#');
char tempChar, tempPopedChar;
//Step 2. Process the string. For a string,length() is a method
//instead of a member variable.
for (int i = 0; i < paraString.length(); i++) {
tempChar = paraString.charAt(i);
switch (tempChar) {
case '(', '[', '{':
tempStack.push(tempChar);
break;
case ')':
tempPopedChar = tempStack.pop();
if (tempPopedChar != '(') {
return false;
}
break;
case ']':
tempPopedChar = tempStack.pop();
if (tempPopedChar != '[') {
return false;
}
break;
case '}':
tempPopedChar = tempStack.pop();
if (tempPopedChar != '{') {
return false;
}
break;
default:
//Do nothing.
}
}
tempPopedChar = tempStack.pop();
if (tempPopedChar != '#') {
return false;
}
return true;
}
public static void main(String args[]) {
CharStack tempStack = new CharStack();
for (char ch = 'a'; ch < 'm'; ch++) {
tempStack.push(ch);
System.out.println("The current stack is: " + tempStack);
} // Of for i
char tempChar;
for (int i = 0; i < 12; i++) {
tempChar = tempStack.pop();
System.out.println("Poped: " + tempChar);
System.out.println("The current stack is: " + tempStack);
} // Of for i
boolean tempMatch;
String tempExpression = "[2 + (1 - 3)] * 4";
tempMatch = bracketMatching(tempExpression);
System.out
.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);
tempExpression = "( ) )";
tempMatch = bracketMatching(tempExpression);
System.out
.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);
tempExpression = "()()(())";
tempMatch = bracketMatching(tempExpression);
System.out
.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);
tempExpression = "({}[])";
tempMatch = bracketMatching(tempExpression);
System.out
.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);
tempExpression = ")(";
tempMatch = bracketMatching(tempExpression);
System.out
.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);
}// Of main
}
栈:首先定义一个最大深度,成员变量有depth和一个字符串数组,然后定义空参构造,成员方法有toString/push/pop
字符串匹配定义一个boolean成员方法,先输入一个‘#’,switch语句进行匹配。
第 16 天: 递归
16.1 递归这个东东, 能理解的同学秒懂, 理解不了的就简直没任何办法.
16.2 数学式子写出来了, 直接翻译成程序, 简单方便.
16.3 系统会为递归建栈, 这个需要理解一下. 例如, 累加程序, 空间复杂度是 O ( n ) O(n)O(n), 因为只有运行到 paraN = 1 时, 才会弹栈.
16.4 Hanoi 问题虽然很有名, 但它更多的是对形参/实参的理解, 所以不写在这里给读者添堵. 再说了, 那种极端的例子也不具有代表性.
package linear_data_structure;
public class Recursion {
//Sum to N. No loop, however a stack is used.
public static int sumTnN(int paraN) {
if (paraN <= 0) {
return 0;
}
return sumTnN(paraN-1) + paraN;
}
//fibonacci
public static int fibonacci(int paraN) {
if (paraN <= 0) {
return 0;
}
if (paraN == 1) {
return 1;
}
return fibonacci(paraN - 1) + fibonacci(paraN - 2);
}
public static void main(String[] args) {
int tempValue = 5;
System.out.println("0 sum to " + tempValue + " = " + sumTnN(tempValue));
tempValue = -1;
System.out.println("0 sum to " + tempValue + " = " + sumTnN(tempValue));
for (int i = 0; i < 10; i++) {
System.out.println("Fibonacci " + i + ": " + fibonacci(i));
}
}
}
递归Recursion,在c语言和py中已经用过很多了,这里不在赘述
第 17 天: 链队列
17.1 链队列比较容易写.
17.2 Node 类以前是 LinkdedList 的内嵌类, 这里重写了一遍. 访问控制的事情以后再说.
17.3 为方便操作, 空队列也需要一个节点. 这和以前的链表同理. 头节点的引用 (指针) 称为 header.
17.4 入队仅操作尾部, 出队仅操作头部.
package linear_data_structure;
public class LinkedQueue {
class Node {
int data;
Node next;
public Node(int paraValue) {
data = paraValue;
next = null;
}
}
Node header;
Node tail;
public LinkedQueue() {
header = new Node(-1);
tail = header;
}
public void enqueue(int paraValue) {
Node tempNode = new Node(paraValue);
tail.next = tempNode;
tail = tempNode;
}
public int dequeue() {
if (header == tail) {
System.out.println("No element in the queue");
return -1;
}
int resultValue = header.next.data;
header.next = header.next.next;
if (header.next == null) {
tail = header;
}
return resultValue;
}
public String toString() {
String resultString = "";
if (header.next == null) {
System.out.println("empty");
}
Node tempNode = header.next;
while (tempNode != null) {
resultString += tempNode.data + ", ";
tempNode = tempNode.next;
}
return resultString;
}
public static void main(String[] args) {
LinkedQueue tempQueue = new LinkedQueue();
System.out.println("Initialized, the list is: " + tempQueue.toString());
for (int i = 0; i < 5; i++) {
tempQueue.enqueue(i+1);
}
System.out.println("Enqueue, the queue is: " + tempQueue.toString());
tempQueue.dequeue();
System.out.println("Dequeue, the queue is: " + tempQueue.toString());
int tempValue;
for (int i = 0; i < 5; i++) {
tempValue = tempQueue.dequeue();
System.out.println("Looped delete " + tempValue + ",the queue is: " + tempQueue.toString());
}
for (int i = 0; i < 3; i++) {
tempQueue.enqueue(i + 10);
} // Of for i
System.out.println("Enqueue, the queue is: " + tempQueue.toString());
}
}
在链队列这个应用类中,首先定义Node类,Node类中包括成员变量和全参构造方法,然后定义链队列的成员变量:header和tail,空参构造,成员方法enqueue、dequeue、toString。
要注意的是,队列中永远有个多的节点,也就是空队列中也有一个节点使头尾节点指向它,tail节点指向最后包含数据元素的节点,而header节点指向多的那个节点,header节点的next节点才是指向第一个包含数据元素的节点。
另外,注意空队列的状态,使头尾节点指向同一节点。