学习来源:日撸 Java 三百行(11-20天,线性数据结构)_闵帆的博客——CSDN博客
一、操作受限的线性表——栈
1. 栈的定义
栈是一种只允许在一端进行插入和删除操作的线性表。允许进行插入和删除操作的一端称为栈顶,对应的另一端为栈底。栈的特点是后进先出(后进进栈的元素会比先进栈的元素先出栈)。
2. 栈有初始化、进栈、出栈、读栈顶等操作。
package JavaDay4;
/**
* @author Kexiong Wang
*
* @date 2022年4月17日
*/
public class Stack {
//栈的空间上限
public static final int MAX_SIZE = 10;
//栈顶
int top;
//栈的存储空间
char[] data;
/**
***********
* 栈的构造函数
* 创建一个空栈
***********
*/
public Stack() {
top = -1;
data = new char[MAX_SIZE];
}//Of Stack
/**
***********
* 重写toString方法,将栈中元素以字符串输出
***********
*/
public String toString() {
String resultString = "";
if(top == -1) {
return "Empty";
}//Of if
for(int i = 0; i <= top; i++) {
resultString += data[i];
}//Of for i
return resultString;
}//Of toString
/**
***********
* 入栈
*
* @param paraChar 入栈元素
* @return 返回入栈结果
***********
*/
public boolean push(char paraChar) {
if(top + 1 == MAX_SIZE) {
System.out.println("Stack is full!");
return false;
}//Of if
data[++top] = paraChar;
return true;
}//Of push
/**
***********
* 出栈
*
* @return 返回出栈元素
***********
*/
public char pop() {
if(top == -1) {
System.out.println("Stack is empty!");
return '\0';
}//Of if
char tempChar = data[top--];
return tempChar;
}//Of pop
/**
***********
* 程序入口
*
* @param args 暂未使用
***********
*/
public static void main(String[] args) {
Stack stack = new Stack();
System.out.println("The initialized stack is: " + stack.toString());
for(char ch = 'a';ch < 'h'; ch ++) {
stack.push(ch);
}//Of for ch
System.out.println("After pushed, the stack is: " + stack.toString());
char tempChar = stack.pop();
System.out.println("The top is: " + tempChar + ", after popped, the stack is: " + stack.toString());
}//Of main
}//Of class Stack
运行结果
3. 栈的应用——括号匹配
package JavaDay4;
/**
* @author Kexiong Wang
*
* @date 2022年4月17日
*/
public class StackForBracketMatching {
//栈的空间上限
public static final int MAX_SIZE = 10;
//栈顶
int top;
//栈的存储空间
char[] data;
/**
***********
* 栈的构造函数
* 创建一个空栈
***********
*/
public StackForBracketMatching() {
top = -1;
data = new char[MAX_SIZE];
}//Of StackForBracketMatching
/**
***********
* 重写toString方法,将栈中元素以字符串输出
***********
*/
public String toString() {
String resultString = "";
if(top == -1) {
return "Empty";
}//Of if
for(int i = 0; i <= top; i++) {
resultString += data[i];
}//Of for i
return resultString;
}//Of toString
/**
***********
* 入栈
*
* @param paraChar 入栈元素
* @return 返回入栈结果
***********
*/
public boolean push(char paraChar) {
if(top + 1 == MAX_SIZE) {
System.out.println("Stack is full!");
return false;
}//Of if
data[++top] = paraChar;
return true;
}//Of push
/**
***********
* 出栈
*
* @return 返回出栈元素
***********
*/
public char pop() {
if(top == -1) {
System.out.println("Stack is empty!");
return '\0';
}//Of if
char tempChar = data[top--];
return tempChar;
}//Of pop
/**
***********
* 括号匹配
*
* @param paraString 传入的进行括号匹配的表达式
* @return 是否匹配
***********
*/
public boolean isMatch(String paraString) {
StackForBracketMatching stack = new StackForBracketMatching();
stack.push('#');
char tempPushChar,tempPopChar;
for(int i = 0; i < paraString.length(); i++) {
tempPushChar = paraString.charAt(i);
switch (tempPushChar) {
case '(':
case '[':
case '{':
stack.push(tempPushChar);
break;
case ')':
tempPopChar = stack.pop();
if(tempPopChar != '(') {
return false;
}//Of if
break;
case ']':
tempPopChar = stack.pop();
if(tempPopChar != '[') {
return false;
}//Of if
break;
case '}':
tempPopChar = stack.pop();
if(tempPopChar != '{') {
return false;
}//Of if
break;
default:
}//Of switch
}//Of for i
tempPopChar = stack.pop();
if(tempPopChar != '#') {
return false;
}//Of if
return true;
}//Of isMatch
/**
***********
* 程序入口
*
* @param args 暂未使用
***********
*/
public static void main(String[] args) {
StackForBracketMatching stack = new StackForBracketMatching();
String tempString1 = "[2 * (1 + 1)]";
System.out.print("The tempString " + tempString1 + " is ");
if(!stack.isMatch(tempString1)) {
System.out.print("not ");
}//Of if
System.out.println("bracket matching.");
String tempString2 = "[2 * (1 + 1)}";
System.out.print("The tempString " + tempString2 + " is ");
if(!stack.isMatch(tempString2)) {
System.out.print("not ");
}//Of if
System.out.println("bracket matching.");
}//Of main
}//Of class StackBracketMatching
运行结果
4. 栈的应用——递归
递归是指在一个函数、过程或数据结构的定义中又应用了自身,则这个函数、过程或数据结构就称是递归定义的。递归可以将一个大型的复杂问题转化为层层嵌套的规模较小的问题,很大程度得减少了代码量,但效率普遍不高。
package JavaDay4;
/**
* @author Kexiong Wang
*
* @date 2022年4月17日
*/
public class StackForRecursion {
/**
***********
* 1到n的累加
*
* @param paraValue 给定的累加上限
* @return 累加的和
***********
*/
public static int sumToN(int paraValue) {
if(paraValue <= 0) {
return 0;
}//Of if
return sumToN(paraValue - 1) + paraValue;
}//Of sumToN
/**
***********
* 斐波那契数列
*
* @param paraValue 给定的值
* @retuen 数列某项值
***********
*/
public static int sumFibonacci(int paraValue) {
if(paraValue <= 0) {
return 0;
}//Of if
if(paraValue == 1) {
return 1;
}//Of if
return sumFibonacci(paraValue - 1) + sumFibonacci(paraValue - 2);
}//Of sumFibonacci
/**
***********
* 程序入口
*
* @param args 暂未使用
***********
*/
public static void main(String[] args) {
int tempValue1 = 20;
int tempValue2 = 8;
System.out.println("Add from 1 to 20 is: " + sumToN(tempValue1));
System.out.println("The 8th number of fibonacci is: " + sumFibonacci(tempValue2));
}//Of main
}//Of class StackForRecursion
运行结果
二、操作受限的线性表——队列
1. 队列的定义
队列只允许在表的一端进行插入,在另一端进行删除。插入元素称入队,删除元素称出队。队列的特点是先进先出。
2. 队列的顺序存储
package JavaDay4;
/**
* @author Kexiong Wang
*
* @date 2022年4月17日
*/
public class SequenceQueue {
//最大队长
public static final int MAX_SIZE = 10;
//队头
int front;
//队尾
int rear;
//队列存储空间
char[] data;
/**
***********
* 初始化
***********
*/
public SequenceQueue() {
front = rear = 0;
data = new char[MAX_SIZE];
}//Of SequenceQueue
/**
***********
* 输出队列的toString方法
***********
*/
public String toString() {
String resultString = "";
if(front == rear) {
return "The queue is empty!";
}//Of if
for(int i = front; i < rear; i ++) {
resultString += data[i];
}//Of for i
return resultString;
}//Of toString
/**
***********
* 入队
*
* @param paraCh 入队的元素
* @return 入队是否成功
***********
*/
public boolean enQueue(char paraCh) {
if(rear >= MAX_SIZE) {
System.out.println("The queue is full!");
return false;
}//Of if
data[rear++] = paraCh;
return true;
}//Of enQueue
/**
***********
* 出队
*
* @return 出队是否成功
***********
*/
public boolean deQueue() {
if(front == rear) {
System.out.println("The queue is empty!");
return false;
}//Of if
front ++;
return true;
}//Of deQueue
/**
***********
* 程序入口
*
* @param args 暂未使用
***********
*/
public static void main(String[] args) {
SequenceQueue sequenceQueue = new SequenceQueue();
System.out.println("After initialized, the queue is: " + sequenceQueue.toString());
for(char ch = 'a'; ch < 'h'; ch ++) {
sequenceQueue.enQueue(ch);
}//Of for ch
System.out.println("After enqueue, the queue is: " + sequenceQueue.toString());
sequenceQueue.deQueue();
System.out.println("After dequeue, the queue is: " + sequenceQueue.toString());
}//Of main
}//Of class SequenceQueue
运行结果
3. 循环队列
在使用顺序队列过程中发现,在队列经过若干次的入队出队操作后,出现rear=MAX_SIZE的情况,此时无法再进行入队操作,但队列中可能还存在可以存储元素的空间。
为了解决上述问题,引入循环队列的概念。循环队列并不是物理上的循环,而是把存储队列元素的表在逻辑上视为一个环。
package JavaDay4;
import javax.annotation.processing.SupportedSourceVersion;
/**
* @author Kexiong Wang
*
* @date 2022年4月17日
*/
public class CircleQueue {
//最大队长
public static final int MAX_SIZE = 10;
//队头
int front;
//队尾
int rear;
//队列存储空间
char[] data;
/**
***********
* 初始化
***********
*/
public CircleQueue() {
front = rear = 0;
data = new char[MAX_SIZE];
}//Of CircleQueue
/**
***********
* 输出队列的toString方法
***********
*/
public String toString() {
String resultString = "";
if(front == rear) {
return "The queue is empty!";
}//Of if
if(front < rear) {
for(int i = front; i < rear; i ++) {
resultString += data[i];
}//Of for i
} else {
for(int j = front; j < MAX_SIZE; j ++) {
resultString += data[j];
}//Of for j
for(int k = 0; k < rear; k ++) {
resultString += data[k];
}//Of for k
}//Of if else
return resultString;
}//Of toString
/**
***********
* 入队
*
* @param paraCh 入队的元素
* @return 入队是否成功
***********
*/
public boolean enQueue(char paraCh) {
if(((rear + 1) % 10) == front) {
System.out.println("The queue is full!");
return false;
}//Of if
data[rear] = paraCh;
rear = (rear + 1) % 10;
return true;
}//Of enQueue
/**
***********
* 出队
*
* @return 出队是否成功
***********
*/
public boolean deQueue() {
if(front == rear) {
System.out.println("The queue is empty!");
return false;
}//Of if
front = (front + 1) % 10;
return true;
}//Of deQueue
/**
***********
* 程序入口
*
* @param args 暂未使用
***********
*/
public static void main(String[] args) {
CircleQueue circleQueue = new CircleQueue();
System.out.println("After initialized, the queue is: " + circleQueue.toString());
for(char ch = 'a'; ch < 'j'; ch ++) {
circleQueue.enQueue(ch);
}//Of for ch
System.out.println("After enqueue, the queue is: " + circleQueue.toString());
System.out.print("Attempt to enqueue character x: ");
circleQueue.enQueue('x');
circleQueue.deQueue();
circleQueue.enQueue('x');
System.out.println("After dequeue and enqueue character x, the queue is: " + circleQueue.toString());
}//Of main
}//Of class CircleQueue
运行结果
三、线性表应用——字符串匹配
package JavaDay4;
/**
* @author Kexiong Wang
*
* @date 2022年4月17日
*/
public class MyString {
//最大长度
public static final int MAX_LENGTH = 10;
//实际长度
int length;
//存字符串
char[] data;
/**
***********
* 无参构造函数,创建空字符串
***********
*/
public MyString() {
length = 0;
data = new char[MAX_LENGTH];
}//Of MyString
/**
***********
* 带参构造函数
*
* @param paraString 用来初始化的字符串
***********
*/
public MyString(String paraString) {
length = paraString.length();
data = new char[MAX_LENGTH];
for(int i = 0; i < length; i ++) {
data[i] = paraString.charAt(i);
}//Of for i
}//Of MyString
/**
***********
* 转为字符串
***********
*/
public String toString() {
String resultString = "";
for(int i = 0; i < length; i ++) {
resultString += data[i];
}//Of for i
return resultString;
}//Of toString
/**
***********
* 定位子串
*
* @param subString 要查找的子串
* @return 第一个匹配子串的位置,-1表示为匹配到子串
***********
*/
public int subStringMatch(MyString subString) {
boolean flag = false;
for(int i = 0; i <= (length - subString.length); i ++) {
flag = true;
for(int j = 0; j < subString.length; j ++) {
if(data[i + j] != subString.data[j]) {
flag = false;
break;
}//Of if
}//Of for j
if(flag) {
return i + 1;
}//Of if
}//Of for i
return -1;
}//Of subStringMatch
/**
***********
* 截取子串
*
* @param paraPosition 截取子串的起点
* @param paraLength 截取子串的长度
***********
*/
public MyString subString(int paraPosition, int paraLength) {
if((paraPosition - 1 + paraLength) > length) {
System.out.println("The bound is exceeded!");
return null;
}//Of if
MyString resultString = new MyString();
resultString.length = paraLength;
for(int i = 0; i < paraLength; i ++) {
resultString.data[i] = data[paraPosition - 1 +i];
}//Of for i
return resultString;
}//Of subString
/**
***********
* 程序入口
*
* @param args 暂未使用
***********
*/
public static void main(String[] args) {
MyString myString = new MyString("Iambruce");
MyString subString = new MyString("uce");
System.out.println("The position of \"" + subString + "\" in \"" + myString + "\" is " + myString.subStringMatch(subString));
int paraPosition = 4;
int paraLength = 5;
System.out.println("The substring of \"" + myString + "\" from " + paraPosition + " to " + 9 + " is \"" + myString.subString(paraPosition,paraLength) + "\"");
}//Of main
}//Of class MyString
运行结果
四、总结
主要学习了操作受限的线性表——栈的队列的基本添加元素、删除元素的操作。以及栈和队列的应用。
其中顺序栈与链栈(顺序队列、循环队列与链队列)的区别从本质上来说是顺序表与链表的区别。顺序表的优点是逻辑结构与物理结构具有一致性,方便查找元素。而链表的优点在于添加和删除元素时的操作较顺序表要简单许多。