继续跟着闵老师的Java 程序设计基础学习,11-20天的内容主要树线性数据结构的代码实现。
11. 第 11 天: 顺序表(一)
11.1 一些数据结构的知识
基本概念和术语:
- 数据:描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。
- 数据元素:组成数据的、有一定意义的基本单位,在计算机中通常作为整体处理。
- 数据项:一个数据元素可以由若干个数据项组成。(不可分割)
- 数据对象:性质相同的数据元素的集合,是数据的子集。
- 数据结构:数据结构是计算机存储、组织数据的方式。 相互之间存在一种或多种特定关系的数据元素的集合。
数据结构分类:
- 数据结构可分为逻辑结构和物理结构。
- 逻辑结构:集合结构、线性结构、树形结构、图形结构
- 物理结构:顺序存储结构、链式存储结构
抽象数据类型:
- 数据类型:指一组性质相同的值的集合及定义在此集合上的一些操作的总称。(可分为原子类型和结构类型)
- 抽象数据类型:指一个数学模型和定义在该模型上的一组操作。
- 数据结构用“抽象数据类型”来描述不同的数据结构,《面向对象程序设计》中, 用对象来存储数据及其上的操作。这里的抽象数据类型甚至可以和对象对应起来。但是,我个人认为从定义上来讲“抽象数据类型”的范围远远大于对象。?
11.2 顺序存储结构
定义:把数据元素存放在地址连续的存储单元里。
线性表的顺序结构:
结构代码:
#defindn MAXSIZE 20
typedef int ElemType;
type struct{
ElemType data[MAXSIZE];
int length;
}SqLIst;
注意:
- data起始位置
- MAXSIZE最大容量
- length长度(length <= MAXSIZE)
package day11;
/**
* Sequential list.
*
* @author He Jia
*/
public class SequentialList {
/**
* The maximal length of the list. It is a constant.
*/
public static final int MAX_LENGTH = 10;
/**
* The actual length not exceeding MAX_LENGTH. Attention: length is not only
* the member variable of Sequential list, but also the member variable of
* Array. In fact, a name can be the member variable of different classes.
*/
int length;
/**
* The data stored in an array.
*/
int[] data;
/**
*********************
* Construct an empty sequential list.
*********************
*/
public SequentialList() {
length = 0;
data = new int[MAX_LENGTH];
}// Of the first constructor
/**
*********************
* Construct a sequential list using an array.
*
* @param paraArray
* The given array. Its length should not exceed MAX_LENGTH. For
* simplicity now we do not check it.
*********************
*/
public SequentialList(int[] paraArray) {
data = new int[MAX_LENGTH];
length = paraArray.length;
// Copy data.
for (int i = 0; i < paraArray.length; i++) {
data[i] = paraArray[i];
} // Of for i
}// Of the second constructor
/**
*********************
* Overrides the method claimed in Object, the superclass of any class.
*********************
*/
public String toString() {
String resultString = "";
if (length == 0) {
return "empty";
} // Of if
for (int i = 0; i < length - 1; i++) {
resultString += data[i] + ", ";
} // Of for i
resultString += data[length - 1];
return resultString;
}// Of toString
/**
*********************
* Reset to empty.
*********************
*/
public void reset() {
length = 0;
}// Of reset
/**
*********************
* The entrance of the program.
*
* @param args Not used now.
*********************
*/
public static void main(String[] args) {
int[] tempArray = { 1, 4, 6, 9 };
SequentialList tempFirstList = new SequentialList(tempArray);
System.out.println("Initialized, the list is: " + tempFirstList.toString());
System.out.println("Again, the list is: " + tempFirstList);
tempFirstList.reset();
System.out.println("After reset, the list is: " + tempFirstList);
}// Of main
}// Of class SequentialList
注意:
- 抄写的时候把默认构造函数漏掉了,且把默认构造函数中的length = 0写到了public SequentialList(int[] paraArray)中,导致得到的结果是empty。
- 如果没有给SequentialList对象重写toString方法,则会调用默认的Object中的toString方法。
- 在类中可以调用该类。
12. 第 12 天: 顺序表(二)
12.1 顺序表中数据的插入和删除
插入的思想:
//初始条件:顺序线性表已经存在
//操作结果:在L中的第i个位置之前插入新的数据元素e,L的长度加1
Statue ListInsert ( SqList *L, int i, ElemType e ){
int k;
if (L->length == MAXSIZE) //顺序表已满
return ERROR;
if ( i < 1 || i > L->length) //i不在范围内时
return ERROR;
if ( i <= L -> length){
for (k = L -> length - 1; k > i - 1; k--){
L -> data[k+1] = L -> data[k];
}
}
L->data[i-1] = e;
L->length++;
return OK;
}
删除思想:
//初始条件: 顺序线性表L已经存在, 1 <= i <= ListLength(L)
// 操作结果: 删除L的第i个数据元素, 并且e返回其值, L的长度减1
Status ListDelete (SqList *L, int i, ElemType *e) {
int k;
if ( L -> length == 0) //线性表为空
return ERROR;
if ( i < 1 || i > L -> length) //删除位置不正确
return ERROR;
*e = L -> data[i-1];
if ( i < L -> length ){
for ( k =i; k < L -> length; k++ )
L -> data[k-1] = L -> data[k];
}
L -> length--;
return OK;
}
12.2 代码编写
package day11;
/**
* Sequential list.
*
* @author He Jia
*/
public class SequentialList {
/**
* The maximal length of the list. It is a constant.
*/
public static final int MAX_LENGTH = 10;
/**
* The actual length not exceeding MAX_LENGTH. Attention: length is not only
* the member variable of Sequential list, but also the member variable of
* Array. In fact, a name can be the member variable of different classes.
*/
int length;
/**
* The data stored in an array.
*/
int[] data;
/**
*********************
* Construct an empty sequential list.
*********************
*/
public SequentialList() {
length = 0;
data = new int[MAX_LENGTH];
}// Of the first constructor
/**
*********************
* Construct a sequential list using an array.
*
* @param paraArray
* The given array. Its length should not exceed MAX_LENGTH. For
* simplicity now we do not check it.
*********************
*/
public SequentialList(int[] paraArray) {
data = new int[MAX_LENGTH];
length = paraArray.length;
// Copy data.
for (int i = 0; i < paraArray.length; i++) {
data[i] = paraArray[i];
} // Of for i
}// Of the second constructor
/**
*********************
* Overrides the method claimed in Object, the superclass of any class.
*********************
*/
public String toString() {
String resultString = "";
if (length == 0) {
return "empty";
} // Of if
for (int i = 0; i < length - 1; i++) {
resultString += data[i] + ", ";
} // Of for i
resultString += data[length - 1];
return resultString;
}// Of toString
/**
*********************
* Reset to empty.
*********************
*/
public void reset() {
length = 0;
}// Of reset
/**
*********************
* Find the index of the given value. If it appears in multiple positions,
* simply return the first one.
*
* @param paraValue The given value.
* @return The position. -1 for not found.
*********************
*/
public int indexOf (int paraValue) {
int tempPosition = -1;
for(int i = 0; i < length; i++) {
if (data[i] == paraValue) {
tempPosition = i;
break;
} //Of if
} // Of for i
return tempPosition;
}// Of indexOf
/**
*********************
* Insert a value to a position. If the list is already full, do nothing.
*
* @param paraPosition The given position.
* @param paraValue The given value.
* @return Success or not.
*********************
*/
public boolean insert(int paraPosition, int paraValue) {
if(length == MAX_LENGTH) {
System.out.println("List full.");
return false;
} // Of if
if((paraPosition < 0) || (paraPosition > length)) {
System.out.println("The position " + paraPosition + " is out of bounds.");
return false;
} // Of if
// From tail to head. The last one is moves to a new position. Because lengrh < MAX_LENGTH, no exceeding occurs.
for (int i = length; i > paraPosition; i--) {
data[i] = data[i-1];
} // Of for i
data[paraPosition] = paraValue;
length++;
return true;
}
/**
*********************
* Delete a value at a position.
*
* @param paraPosition The given position.
* @return Success or not.
*********************
*/
public boolean delete(int paraPosition) {
if ((paraPosition < 0) || (paraPosition >= length)) {
System.out.println("The position " + paraPosition + " is out of bounds.");
return false;
} // Of if
// From head to tail.
for (int i = paraPosition; i < length - 1; i++) {
data[i] = data[i + 1];
} // Of for i
length--;
return true;
}// Of delete
/**
*********************
* The entrance of the program.
*
* @param args Not used now.
*********************
*/
public static void main(String[] args) {
int[] tempArray = { 1, 4, 6, 9 };
SequentialList tempFirstList = new SequentialList(tempArray);
System.out.println("Initialized, the list is: " + tempFirstList.toString());
System.out.println("Again, the list is: " + tempFirstList);
int tempValue = 4;
int tempPosition = tempFirstList.indexOf(tempValue);
System.out.println("The position of " + tempValue + " is " + tempPosition);
tempValue = 5;
tempPosition = tempFirstList.indexOf(tempValue);
System.out.println("The position of " + tempValue + " is " + tempPosition);
tempPosition = 2;
tempValue = 5;
tempFirstList.insert(tempPosition, tempValue);
System.out.println(
"After insertiong " + tempValue + " to position " + tempPosition + ", the list is: " + tempFirstList);
tempPosition = 8;
tempValue = 10;
tempFirstList.insert(tempPosition, tempValue);
System.out.println(
"After insertiong " + tempValue + " to position " + tempPosition + ", the list is: " + tempFirstList);
tempPosition = 3;
tempFirstList.delete(tempPosition);
System.out.println("After deleting data at position " + tempPosition + ", the list is: " + tempFirstList);
for (int i = 0; i < 8; i++) {
tempFirstList.insert(i, i);
System.out.println("After inserting " + i + " to position " + i + ", the list is: " + tempFirstList);
} // Of for i
tempFirstList.reset();
System.out.println("After reset, the list is: " + tempFirstList);
}// Of main
}// Of class SequentialList
13.第 13 天: 链表
13.1 关于链式存储结构
单链表的读取(获取第i个数据元素):
- 声明节点p,初始化j = 1;
- j < i,遍历链表,让p向后移动, p -> p.next, j++;(表的长度不明使用while)
- 如果 p == null,则第i个元素不存在;
- 否则查找成功。
单链表的插入(插入到第i个数据):
- 声明节点p,初始化j = 1;
- j < i,遍历链表,让p向后移动, p -> p.next, j++;(表的长度不明使用while)
- 如果 p == null,则第i个元素不存在;
- 否则查找成功,生成一个空节点;
- 将元素e赋值给s -> data;
- 插入标准语句:s -> next = p -> next; p ->next =s;
- 返回成功。
单链表的删除(删除到第i个数据):
- 声明节点p,初始化j = 1;
- j < i,遍历链表,让p向后移动, p -> p.next, j++;(表的长度不明使用while)
- 如果 p == null,则第i个元素不存在;
- 否则查找成功,将删除的节点p -> next 赋值给q;
- 删除标准语句:p -> next = q -> next;
- *e = q -> data;
- 释放q节点;
- 返回成功。
单链表的整表创建(已知表的长度使用for)
单链表的整表删除(表的长度不明使用while)
13.2 LinkedList.java编写
package day12;
/**
* Linked list.
*
* @author He Jia
*/
public class LinkedList {
/**
* An inner class.
*/
class Node {
/**
* The data.
*/
int data;
/**
* The reference to the next node.
*/
Node next;
/**
*******************
* The constructor
*
* @param paraValue The data.
*******************
*/
public Node(int paraValue) {
data = paraValue;
next = null;
}// Of the constructor
}// Of class Node
/**
* The header node. The data is never used.
*/
Node header;
/**
*********************
* Construct an empty linked list.
*********************
*/
public LinkedList() {
header = new Node(0);
// header.next = null; //Redundant
}// Of the first constructor
/**
*********************
* Overrides the method claimed in Object, the superclass of any class.
*********************
*/
public String toString() {
String resultString = "";
if (header.next == null) {
return "empty";
} // Of if
Node tempNode = header.next;
while (tempNode != null) {
resultString += tempNode.data + ", ";
tempNode = tempNode.next;
} // Of while
return resultString;
}// Of toString
/**
*********************
* Reset to empty. Free the space through garbage collection.
*********************
*/
public void reset() {
header.next = null;
}// Of reset
/**
*********************
* Locate the given value. If it appears in multiple positions, simply return
* the first one.
*
* @param paraValue The given value.
* @return The position. -1 for not found.
*********************
*/
public int locate(int paraValue) {
int tempPosition = -1;
Node tempNode = header.next;
int tempCurrentPosition = 0;
while (tempNode != null) {
if (tempNode.data == paraValue) {
tempPosition = tempCurrentPosition;
break;
} // Of if
tempNode = tempNode.next;
tempCurrentPosition++;
} // Of while
return tempPosition;
}// Of locate
/**
*********************
* Insert a value to a position. If the list is already full, do nothing.
*
* @param paraPosition The given position.
* @param paraValue The given value.
* @return Success or not.
*********************
*/
public boolean insert(int paraPosition, int paraValue) {
Node tempNode = header;
Node tempNewNode;
for (int i = 0; i < paraPosition; i++) {
if (tempNode.next == null) {
System.out.println("The position " + paraPosition + " is illegal.");
return false;
} // Of if
tempNode = tempNode.next;
} // Of for i
// Construct a new node.
tempNewNode = new Node(paraValue);
// Now link them.
tempNewNode.next = tempNode.next;
tempNode.next = tempNewNode;
return true;
}// Of insert
/**
*********************
* Delete a value at a position.
*
* @param paraPosition The given position.
* @return Success or not.
*********************
*/
public boolean delete(int paraPosition) {
if (header.next == null) {
System.out.println("Cannot delete element from an empty list.");
return false;
} // Of if
Node tempNode = header;
for (int i = 0; i < paraPosition; i++) {
if (tempNode.next.next == null) {
System.out.println("The position " + paraPosition + " is illegal.");
return false;
} // Of if
tempNode = tempNode.next;
} // Of for i
tempNode.next = tempNode.next.next;
return true;
}// Of delete
/**
*********************
* The entrance of the program.
*
* @param args Not used now.
*********************
*/
public static void main(String args[]) {
LinkedList tempFirstList = new LinkedList();
System.out.println("Initialized, the list is: " + tempFirstList.toString());
for (int i = 0; i < 5; i++) {
tempFirstList.insert(0, i);
} // Of for i
System.out.println("Inserted, the list is: " + tempFirstList.toString());
tempFirstList.insert(6, 9);
tempFirstList.delete(4);
tempFirstList.delete(2);
System.out.println("Deleted, the list is: " + tempFirstList.toString());
tempFirstList.delete(0);
System.out.println("Deleted, the list is: " + tempFirstList.toString());
for (int i = 0; i < 5; i++) {
tempFirstList.delete(0);
System.out.println("Looped delete, the list is: " + tempFirstList.toString());
} // Of for i
}// Of main
}// Of LinkedList
两个问题:
- 链表中的重置、插入、删除,都只修改了对象中的指针域。但是原有是节点对象依旧存在。这些节点对象是会被Java回收机制回收,如果不被调用话。
- main函数。先创建了一个链表;然后是插入节点;然后是删除节点;最后一个for循环删除使链表为空。使用for循环删除而不用reset是为了对称?
14. 第14天:栈
14.0 其他
通过这几天的学习,我发现笔记还是要写在笔记本上!!!/(ㄒoㄒ)/
14.1 栈的介绍
栈和线性表的不同点在于插入和删除的位置不一样,栈插入和删除都在表尾,遵循LIFO。栈的物理存储方式有顺序存储和链表存储。
14.2 编写CharStack.java
toString、Pop、Push、main
package day14;
/**
* Char stack. We do not Stack beacuse it is already defined in Java.
*
* @author He Jia
*/
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];
}// Of the first constructor
/**
********************
* 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];
} // Of for i
return resultString;
}// Of toSting
/**
*********************
* Push an element.
*
* @param paraChar The given char.
* @return Success or not.
*********************
*/
public boolean push(char paraChar) {
if(depth == MAX_DEPTH) {
return false;
} // Of if
data[depth] = paraChar;
depth++;
return true;
}// Of push
/**
*******************
* Pop an element.
*
* @return The popped char.
********************
*/
public char pop() {
if(depth == 0) {
return '\0';
} // Of if
char resultChar = data[depth - 1];
depth--;
return resultChar;
}// Of pop
/**
********************
* The entrance of the program.
*
* @param args Not used now.
********************
*/
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
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
}// Of main
}// Of CharStack
15. 第15天:栈的应用(括号匹配)
15.1 charAt和代码思路
charAt(int index)方法:是一个能够用来检索特定索引下的字符的String实例的方法。
思路:主要是使用了for循环确定字符串中的每一个字符,然后在里面使用switch方法判断字符是否是 { [ ( ) ] },是 { [ ( 则入栈,是 ) ] } 则使栈中元素出栈。
15.2 编写bracketMatching方法
任务描述:
检查一个字符串的括号是否匹配. 所谓匹配, 是指每个左括号有相应的一个右括号与之对应, 且左括号不可以出现在右括号右边. 可以修改测试字符串, 检查不同情况下的运行.
- 仅在昨天的代码基础上增加了一个 bracketMatching 方法, 以及 main 中的相应调拭语句.
- 操作系统的核心数据结构. 对于计算机而言, 如何降低时间、空间复杂度才是王道.
- 除了关注的括号, 其它字符不起任何作用.
- 一旦发现不匹配, 就直接返回, 不用罗嗦.
package day15;
import day15.CharStack;
/**
* Char stack. We do not Stack because it is already defined in Java.
*
* @author He Jia
*/
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];
}// Of the first constructor
/**
********************
* 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];
} // Of for i
return resultString;
}// Of toSting
/**
*********************
* Push an element.
*
* @param paraChar The given char.
* @return Success or not.
*********************
*/
public boolean push(char paraChar) {
if(depth == MAX_DEPTH) {
return false;
} // Of if
data[depth] = paraChar;
depth++;
return true;
}// Of push
/**
*******************
* Pop an element.
*
* @return The popped char.
********************
*/
public char pop() {
if(depth == 0) {
return '\0';
} // Of if
char resultChar = data[depth - 1];
depth--;
return resultChar;
}// Of pop
public static boolean braketMatching(String paraString) {
// Step 1. Initialize the stack through pushing a '#' at the bottom.
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 '(':
case '[':
case '{':
tempStack.push(tempChar);
break;
case ')':
tempPopedChar = tempStack.pop();
if (tempPopedChar != '(') {
return false;
} // Of if
break;
case ']':
tempPopedChar = tempStack.pop();
if (tempPopedChar != '[') {
return false;
} // Of if
break;
case '}':
tempPopedChar = tempStack.pop();
if(tempPopedChar != '{') {
return false;
} // Of if
break;
default:
// Do noting.
} // Of switch
} // Of for
tempPopedChar = tempStack.pop();
if(tempPopedChar != '#') {
return false;
} // Of if
return true;
}// Of breaketMatching
/**
********************
* The entrance of the program.
*
* @param args Not used now.
********************
*/
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
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
boolean tempMatch;
String tempExpression = "[2 + (1 - 3)] * 4";
tempMatch = braketMatching(tempExpression);
System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);
tempExpression = "( ) )";
tempMatch = braketMatching(tempExpression);
System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);
tempExpression = "()()(())";
tempMatch = braketMatching(tempExpression);
System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);
tempExpression = "({}[])";
tempMatch = braketMatching(tempExpression);
System.out.println("Is the expression " + tempExpression + " bracket matching? " + tempMatch);
tempExpression = ")(";
tempMatch = braketMatching(tempExpression);
System.out.println("Is the expression" + tempExpression + " bracket matching? " + tempMatch);
}// Of main
}// Of CharStack
注意:空格 和 switch case 后面的break!
16. 第16天:递归
16.1 栈的应用
在栈的应用有递归和四则运算表达式求值(递归&&一些问题也可以用for迭代,就是正着和倒着用)。
16.2 编写Recursion.java
- 递归这个东东, 能理解的同学秒懂, 理解不了的就简直没任何办法.
- 数学式子写出来了, 直接翻译成程序, 简单方便.
- 系统会为递归建栈, 这个需要理解一下. 例如, 累加程序, 空间复杂度是 O ( n ) , 因为只有运行到 paraN = 1 时, 才会弹栈.
- 汉诺塔(Hanoi) 问题虽然很有名, 但它更多的是对形参/实参的理解, 所以不写在这里给读者添堵. 再说了, 那种极端的例子也不具有代表性.
本代码是一个斐波那契数列的实现
package day16;
/**
* Recursion. A method can (directly or indirectly) invoke itself. The system
* automatically creates a stack for it.
*
* @author He Jia
*/
public class Recursion {
/**
*********************
* Sum to N. No loop, however a stack is used.
*
* @param paraN
* The given value.
* @return The sum.
*********************
*/
public static int sumToN(int paraN) {
if (paraN <= 0) {
// Basis.
return 0;
} // Of if
return sumToN(paraN - 1) + paraN;
}// Of sumToN
/**
*********************
* Fibonacci sequence.
*
* @param paraN
* The given value.
* @return The sum.
*********************
*/
public static int fibonacci(int paraN) {
if (paraN <= 0) {
// Negative values are invalid. Index 0 corresponds to the first element 0.
return 0;
} if (paraN == 1) {
// Basis.
return 1;
} // Of if
return fibonacci(paraN - 1) + fibonacci(paraN - 2);
}// Of fibonacci
/**
*********************
* The entrance of the program.
*
* @param args
* Not used now.
*********************
*/
public static void main(String[] args) {
int tempValue = 5;
System.out.println("0 sum to " + tempValue + " = " + sumToN(tempValue));
tempValue = -1;
System.out.println("0 sum to " + tempValue + " = " + sumToN(tempValue));
for(int i = 0; i < 10; i++) {
System.out.println("Fibonacci " + i + ": " + fibonacci(i));
} // Of for i
}// Of main
}// Of class Recursion
17. 第 17 天: 链队列
17.1 队列
栈、队列其实都可以算作是一种线性表,只是说对其增删数据的位置做了限定。
17.2 编写LinkedQueue.java
- 链队列比较容易写.
- Node 类以前是 LinkdedList 的内嵌类, 这里重写了一遍. 访问控制的事情以后再说.
- 为方便操作, 空队列也需要一个节点. 这和以前的链表同理. 头节点的引用 (指针) 称为 header.
- 入队仅操作尾部, 出队仅操作头部.
有一个Node内部类,和增添enqueue和删除dequeue两种方法、 toString方法。
package day17;
/**
* Linked queue.
*
* @author He Jia
*/
public class LinkedQueue {
/**
* An inner class.
*/
class Node {
/**
* The data.
*/
int data;
/**
* The reference to the next node.
*/
Node next;
/**
*******************
* The constructor
*
* @param paraValue The data.
*******************
*/
Node(int paraValue) {
data = paraValue;
next = null;
}// Of the constructor
}// Of class Node
/**
* The header of the queue.
*/
Node header;
/**
* The tail of the queue.
*/
Node tail;
/**
*********************
* Construct an empty sequential list.
*********************
*/
public LinkedQueue() {
header = new Node(-1);
// header.next = null;
tail = header;
}// Of the first constructor
/**
**********************
* Enqueue.
*
* @param paraValue The value of the new node.
**********************
*/
public void enqueue(int paraValue) {
Node tempNode = new Node(paraValue) ;
tail.next = tempNode;
tail = tempNode;
}// Of enqueue
/**
********************
* Dequeue.
*
* @return The value at the header.
********************
*/
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;
} // Of if
return resultValue;
}
/**
**********************
* Overrides the method claimed in Object, the superclass of any class.
**********************
*/
public String toString() {
String resultString = "";
if(header.next == null) {
return "empty";
} // Of if
Node tempNode = header.next;
while (tempNode != null) {
resultString += tempNode.data + ", ";
tempNode = tempNode.next;
}
return resultString;
}
/**
*********************
* The entrance of the program.
*
* @param args Not used now.
*********************
*/
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);
} // Of for i
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 new queue is: " + tempQueue.toString());
} // Of for i
for (int i = 0; i < 3; i++) {
tempQueue.enqueue(i + 10);
} // Of for i
System.out.println("Enqueue, the queue is: " + tempQueue.toString());
}// Of main
}// Of class LinkedQueue
注意:我们在运行代码时会发现,当队列已经为空时,再一次调用dequeue方法,会返回 -1。因为dequeue方法的返回值必须是int类型,所以当队列为空时,我们也为它设定了返回值。
18. 第 18 天: 循环队列
18.1链式存储和顺序存储
第17天链队列时队列的链式存储,下面我们来使用顺序存储。
18.2 编写CircleIntQueue.java
- 整除的作用.
- 想像操场跑道里放一队人, 循环的感觉就出来了.
- 为了区分空队列与满队列, 需要留一个空间. 相当于不允许首尾相连. 还是画个图吧, 否则容易进坑.
- 用链式结构, 空间的分配与回收由系统做, 用循环队列, 则是自己把控. 想象自己写的是操作系统, 从这个代码可以感受下内存的管理.
package day18;
/**
* Circle int queue.
*
* @author He Jia
*/
public class CircleIntQueue {
/**
* The total space. One space can never be used.
*/
public static final int TOTAL_SPACE = 10;
/**
* The data.
*/
int data[];
/**
* The index for calculating the head. The actual head is head % TOTAL_SPACE.
*/
int head;
/**
* The index for calculating the tail.
*/
int tail;
/**
******************
* The constructor
******************
*/
public CircleIntQueue() {
data = new int[TOTAL_SPACE];
head = 0;
tail = 0;
}// Of the first CircleIntQueue
/**
**********************
* Enqueue.
*
* @param paraValue The value of the new node.
**********************
*/
public void enqueue(int paraValue) {
if ((tail + 1) % TOTAL_SPACE == head) {
System.out.println("Queue full.");
} // Of if
data[tail % TOTAL_SPACE] = paraValue;
tail++;
}// Of enqueue
/**
********************
* Dequeue.
*
* @return The value at the head.
*********************
*/
public int dequeue() {
if(head == tail) {
System.out.println("No element in the queue");
return -1;
}
int resultValue = data[head % TOTAL_SPACE];
head++;
return resultValue;
}// Of dequeue
/**
**********************
* Overrides the method claimed in Object, the superclass of any class.
**********************
*/
public String toString() {
String resultString = "";
if (head == tail) {
return "empty";
} // Of if
for (int i = head; i < tail; i++) {
resultString += data[i % TOTAL_SPACE] + ", ";
} // Of for i
return resultString;
}// Of toString
public static void main(String[] args) {
CircleIntQueue tempQueue = new CircleIntQueue();
System.out.println("Initialized, the list is: " + tempQueue.toString());
for (int i = 0; i < 5; i++) {
tempQueue.enqueue(i + 1);
} // Of for i
System.out.println("Enqueue, the queue is: " + tempQueue.toString());
int tempValue = tempQueue.dequeue();
System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());
for(int i = 0; i < 6; i++) {
tempQueue.enqueue(i + 10);
System.out.println("Enqueue, the queue is: " + tempQueue.toString());
} // Of for i
for(int i = 0; i < 3; i++) {
tempValue = tempQueue.dequeue();
System.out.println("Dequeue " + tempValue + ", the queue is: " + tempQueue.toString());
} // Of for i
for(int i = 0; i < 6; i++) {
tempQueue.enqueue(i + 100);
System.out.println("Enqueue, the queue is: " + tempQueue.toString());
} // Of for i
}// Of main
}// Of CircleIntQueue
我们在运行程序后会发现,当队列已经满了之后,它会提示栈满。但是当我们继续输入数据时,它会把队列头部的数据改写成新输入的数据。这就是因为我们使用了循环队列, 空间的分配与回收由系统是自己把控的。
19. 第 19 天: 字符串匹配
19.1 charAt()方法
描述:
java.lang.String.charAt() 方法返回指定索引处的char值。索引范围是从0到length() - 1。对于数组索引,序列的第一个char值是在索引为0,索引1,依此类推
以下是声明java.lang.String.charAt()方法:
public char charAt(int index);
使用:
System.out.println("s.charAt(i)");
19.2 编写MyString.java
- String 是 Java 常用的类, 这里重新实现下部分功能.
- 转义符 , 有了它才能正常打印引号.
- 简单的越界检查.
package day19;
/**
* My string. String is a class provided by the language, so we use another name.
* It is essentially a sequential list with char type elements.
*
* @author He Jia
*/
public class MyString {
/**
* The maximal length.
*/
public static final int MAX_LENGTH = 10;
/**
* The actual length.
*/
int length;
/**
* The data.
*/
char[] data;
/**
*********************
* Construct an empty char array.
*********************
*/
public MyString() {
length = 0;
data = new char[MAX_LENGTH];
}// Of the first constructor
/**
*********************
* Construct using a system defined string.
*
* @param paraString The given string. Its length should not exceed MAX_LENGTH -
* 1.
*********************
*/
public MyString(String paraString) {
data = new char[MAX_LENGTH];
length = paraString.length();
// Copy data.
for (int i = 0; i < length; i++) {
data[i] = paraString.charAt(i);
} // Of for i
}// Of the second constructor
/**
*********************
* Overrides the method claimed in Object, the superclass of any class.
*********************
*/
public String toString() {
String resultString = "";
for (int i = 0; i < length; i++) {
resultString += data[i];
} // Of for i
return resultString;
}// Of toString
/**
*********************
* Locate the position of a substring.
*
* @param paraString The given substring.
* @return The first position. -1 for no matching.
*********************
*/
public int locate(MyString paraMyString) {
boolean tempMatch = false;
for (int i = 0; i < length - paraMyString.length + 1; i++) {
// Initialize.
tempMatch = true;
for (int j = 0; j < paraMyString.length; j++) {
if (data[i + j] != paraMyString.data[j]) {
tempMatch = false;
break;
} // Of if
} // Of for j
if (tempMatch) {
return i;
} // Of if
} // Of for i
return -1;
}// Of locate
/**
*********************
* Get a substring
*
* @param paraString The given substring.
* @param paraStartPosition The start position in the original string.
* @param paraLength The length of the new string.
* @return The first position. -1 for no matching.
*********************
*/
public MyString substring(int paraStartPosition, int paraLength) {
if (paraStartPosition + paraLength > length) {
System.out.println("The bound is exceeded.");
return null;
} // Of if
MyString resultMyString = new MyString();
resultMyString.length = paraLength;
for (int i = 0; i < paraLength; i++) {
resultMyString.data[i] = data[paraStartPosition + i];
} // Of for i
return resultMyString;
}// Of substring
/**
*********************
* The entrance of the program.
*
* @param args Not used now.
*********************
*/
public static void main(String args[]) {
MyString tempFirstString = new MyString("I like ik.");
MyString tempSecondString = new MyString("ik");
int tempPosition = tempFirstString.locate(tempSecondString);
System.out.println(
"The position of \"" + tempSecondString + "\" in \"" + tempFirstString + "\" is: " + tempPosition);
MyString tempThirdString = new MyString("ki");
tempPosition = tempFirstString.locate(tempThirdString);
System.out.println(
"The position of \"" + tempThirdString + "\" in \"" + tempFirstString + "\" is: " + tempPosition);
tempThirdString = tempFirstString.substring(1, 2);
System.out.println("The substring is: \"" + tempThirdString + "\"");
tempThirdString = tempFirstString.substring(5, 5);
System.out.println("The substring is: \"" + tempThirdString + "\"");
tempThirdString = tempFirstString.substring(5, 6);
System.out.println("The substring is: \"" + tempThirdString + "\"");
}// Of main
}// Of class MyString
20.第 20 天: 小结
- 面向对象与面向过程相比, 有哪些优势? 注: 第 1 - 10 天的程序, 就是面向过程的.
- 比较线性表和链接的异同.
- 分析线性表和链接的优缺点.
- 分析调试程序常见的问题及解决方案.
- 分析链队列与循环队列的优缺点.
- 第 18 天建立的两个队列, 其区别仅在于基础数据不同, 一个是 int, 一个是 char. 按这种思路, 对于不同的基础数据类型, 都需要重写一个类, 这样合理吗? 你想怎么样?
- 答:面向过程更加符合机器的运行特点而面向对象则更加符合人的思维特点。以机器人拿水杯倒水为例子,如果是面向过程的C、C++则需要,先设置机器人拿到水杯的路线、到饮水机前接水、在设置路线把水杯给人,它需要一步一步的解决问题。如果是面向对象则会,先设置水杯对象、里面有接水的方法、拿到水杯路线的方法。面向过程会更加好理解。
- 都可以进行查找、增加、删除,时间上:线性表查找的时间复杂度是O(1),链表是O(n);线性表增加和删除数据都是O(n) ,链表是O(1). 空间上:线性表需要预分配存储空间,容易产生浪费,且容易上溢,而链表这则需要指针域。
- 线性表查找数据快,增删慢,容易浪费空间,容易溢出;链表查找相对慢,但是增删快,空间利用率高,基本不会溢出。
- 比如写的时候会忘记MAX_LENGTH赋初始值,然后程序报错,就在main中的第一行打一个断点,然后一直step into 。
- 链队列不需要担心数据溢出的问题,时间上和循环队列一样是O(1),但是申请和释放结点需要一些时间,空间上需要一个指针域。循环队列时间也为O(1),但是需要考虑溢出的问题,空间上也存在很大的浪费。
- 不合理,这里我们可以使用到泛型。