kmp算法<部分匹配表>
汉罗塔
线性 栈 队列 列表
非线性 图 树
数据结构(data structrue)
程序 = 数据结构 + 算法
约瑟夫问题
单链表
单向环形链表
稀疏数组
修路问题 -》最小生成树(加权值)【数据结构】 + 普利姆算法
最短路径问题 -》 图+弗洛伊德算法
汉罗塔 -》 分治算法
八皇后问题 -》 回溯法
数据结构(datastructrue)
线性结构 和 非线性结构
1、线性结果作为最常用的数据结构,其特点是数据元素之间存在一对一
的线性关系
2、 线性结构有两种不同的存储结构,即顺序存储结构
和链式存储结构
。顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的
3、 链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放元素以及相邻元素的地址信息
链式结构可以很好的用到碎片内存
4、 线性结构常见的有:数组、队列、链表和栈,
非线性结构:二维数组、多维数组、广义表、树结构、图结构
稀疏数组 和 队列
第一行 分别代表 一共有多少行 一共有多少列 一共有多少非0数据
只存有必要的数据
稀疏数组转变多维数组的存储格式 如上图把6*7的数组
转化成了3*9的数组
二维数组转稀疏数组的思路
1、遍历 原始的二维数组,得到有效数据的个数 sum
2、根据sum就可以创建 稀疏数组 sparseArr int[sum+1][3]
3、将二维数组的有效数据存入到稀疏数组
稀疏数组转原始二维数组的思路
1、先读取读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组,比如上面的原始数组 chessArr2 = int[11][11]
2、再读取稀疏数组后几行的数组,并赋给原始的二维数组即可
代码案例
这里把生成的稀疏数组存到文件里面 这里用Integer包装类方便数字和字符串的转化
然后再取出来,因为java我不是专业的写的可能很丑,逻辑是这样的
package com.company;
public class Main {
// read
public static void main(String[] args) {
Integer[][] arr = new Integer[11][11];
for (Integer i = 0; i < arr.length; i++) {
for (Integer j = 0; j < arr[i].length; j++) {
arr[i][j] = 0;
}
}
arr[1][2] = 1;
arr[2][3] = 2;
arr[3][3] = 2;
for (Integer[] row : arr) {
for (Integer col : row) {
System.out.printf("%d\t", col);
}
System.out.println();
}
int sum = 0;
for (Integer i = 0; i < arr.length; i++) {
for (Integer j = 0; j < arr[i].length; j++) {
if (arr[i][j] != 0) {
sum++;
}
}
}
System.out.println(sum);
// 创建一个对应的稀疏稀疏数组
Integer[][] sparseArr = setSparseArr(sum, arr);
write.writeArray(sparseArr);
for (Integer[] row : sparseArr) {
for (Integer col : row) {
System.out.printf("%d\t", col);
}
System.out.println();
}
System.out.println("---------");
Integer[][] oldArray = reSparseArr(write.readArray(sparseArr));
for (Integer[] row : oldArray) {
for (Integer col : row) {
System.out.printf("%d\t", col);
}
System.out.println();
}
}
// 从稀疏数组回复原数组
private static Integer[][] reSparseArr(Integer[][] sparseArr) {
Integer[][] array = new Integer[sparseArr[0][0]][sparseArr[0][1]];
for (Integer i = 0; i < array.length; i++) {
for (Integer j = 0; j < array[i].length; j++) {
array[i][j] = 0;
}
}
for (Integer i = 1; i < sparseArr.length; i++) {
array[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
}
return array;
}
// 原数组转化位稀疏数组
private static Integer[][] setSparseArr(int sum, Integer[][] array) {
Integer[][] sparseArr = new Integer[sum + 1][3];
int sparseArrIndex = 1;
// 用于记录是第几个非零数据 0位内容已经固定所有从1开始
sparseArr[0][0] = array.length;
sparseArr[0][1] = array[0].length;
sparseArr[0][2] = sum;
for (Integer k = 0; k < array.length; k++) {
for (Integer j = 0; j < array[k].length; j++) {
if (array[k][j] != 0) {
sparseArr[sparseArrIndex][0] = k;
sparseArr[sparseArrIndex][1] = j;
sparseArr[sparseArrIndex][2] = array[k][j];
sparseArrIndex++;
}
}
}
return sparseArr;
}
}
write.js
package com.company;
import java.io.*;
/**
* @author 41395
* @date 2021/10/28
*/
public class write {
public static void writeArray(Integer[][] array) {
try {
// Integer bWrite[][] = array;
OutputStream os = new FileOutputStream("test.txt");
OutputStreamWriter writer = new OutputStreamWriter(os, "UTF-8");
for (int x = 0; x < array.length; x++) {
for (int y = 0; y < array[x].length; y++) {
for (int z = 0; z < array[x][y].toString().length(); z++) {
writer.append(array[x][y].toString().charAt(z));
}
writer.append("列");
}
writer.append("行");
// writes the bytes
}
writer.close();
os.close();
} catch (IOException e) {
System.out.print(e);
}
}
public static Integer[][] readArray(Integer[][] array) {
File f = new File("test.txt");
Integer[][] oldArray = new Integer[0][];
try {
FileInputStream fip = new FileInputStream(f);
// 构建FileInputStream对象
InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
// 构建InputStreamReader对象,编码与写入相同
StringBuffer sb = new StringBuffer();
while (reader.ready()) {
sb.append((char) reader.read());
// 转成char加到StringBuffer对象中
}
System.out.println();
reader.close();
// 关闭读取流
fip.close();
String[] rowList = sb.toString().split("行");
String[] colList;
oldArray = new Integer[rowList.length][3];
for (int i = 0; i < rowList.length; i++) {
colList = rowList[i].split("列");
for (int y = 0; y < colList.length; y++) {
// System.out.println(colList[y]);
oldArray[i][y] = Integer.valueOf(colList[y]);
}
}
} catch (IOException e) {
System.out.print(e);
}
return oldArray;
}
}
test.txt
11列11列3列行1列2列1列行2列3列2列行3列3列2列行
队列
队列是一个有序列表,可以用数组或者链表来实现
遵循先入先出的原则。即:先存入队列的数据,要先取出。后存入的要后取出
队列需要三个变量:最大容量、最前面的指针、最后面的指针
队列
package com.company;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// write your code here
ArrayQueue arrayQueue = new ArrayQueue(3);
char key = '1'; // 接受用户输入
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("s(show):显示队列");
System.out.println("e(exit):推出队列");
System.out.println("a(add):添加队列数据");
System.out.println("g(get):从队列头部取数据");
System.out.println("h(head):查看队列头的数据");
key = scanner.next().charAt(0);
switch (key) {
case 's':
arrayQueue.showQueue();
break;
case 'a':
System.out.println("请输入一个数组");
arrayQueue.addQueue(scanner.nextInt());
break;
case 'g':
try {
System.out.printf("取出的数据是%d", arrayQueue.getQueue());
} catch (RuntimeException err) {
System.out.println(err.getMessage());
}
break;
case 'h':
try {
System.out.printf("查看头数据是%d", arrayQueue.headQueue());
} catch (RuntimeException err) {
System.out.println(err.getMessage());
}
break;
case 'e':
scanner.close();
loop = false;
break;
}
}
System.out.println("程序结束");
}
}
ArrayQueue.java
package com.company;
// 使用数组模拟队列-编写一个ArrayQueue类
public class ArrayQueue {
private int maxSize;
// 表示数组最大容量
private int front;
// 队列头
private int rear;
// 队列尾
private int[] arr;
// 该数据用于存储数据,模拟队列
// 创建队列的构造器
public ArrayQueue(int arrMaxSize){
maxSize = arrMaxSize;
arr = new int[maxSize];
front = -1; // 指向队列头部,分析出front时指向队列头的前一个位置
rear = -1; // 指向队列尾,指向队列尾的数据(即就是队列最后一个数据)
}
public boolean isFull(){
return maxSize - 1 == rear;
}
public boolean isEmpty(){
return front == rear;
}
public void addQueue(int n){
if(isFull()){
System.out.println("队列已满");
return;
}
rear ++; // 让rear后移
arr[rear] = n;
}
// 获取队列的数据,出队列
public int getQueue(){
if(isEmpty()){
// 通过抛出异常来处理
throw new RuntimeException("队列为空");
}
front++; // 让front后移
int queueData = arr[front];
// rear--;
// front --;
// for (int i = 1; i < arr.length; i++) {
// arr[i - 1] = arr[i];
// if(i == arr.length - 1){
// arr[i] = 0;
// }
// }
return queueData;
}
public void showQueue(){
if (isEmpty()){
System.out.println("队列空");
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.printf("arr[%d]=%d\n",i,arr[i]);
}
}
// 显示队列的头是谁,不是取出数据
public int headQueue(){
if (isEmpty()){
throw new RuntimeException("队列为空");
}
return arr[front + 1];
}
}
环形队列
环形队列示例代码
package com.company;
/**
* @author 41395
*/
public class Queue {
private int maxSize;
private int front;
private int rear;
private int[] arr;
// rear = 0;
// front = 2;
// maxSize = 3;
public Queue(int arrMaxSize) {
front = 0;
rear = 0;
maxSize = arrMaxSize;
arr = new int[maxSize];
}
// 0 + 3 - 3 % 3 ==
public boolean isFull() {
return size() + 1 == maxSize;
}
public boolean isEmpty() {
return rear == front;
}
public void addQueue(int n) {
if (isFull()) {
System.out.println("队列满了");
return;
}
arr[rear] = n;
rear = (rear + 1) % maxSize;
}
public int getQueue() {
if (isEmpty()) {
throw new RuntimeException("队列为空,你取啥");
}
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
public void showQueue() {
if (isEmpty()) {
throw new RuntimeException("队列为空,没啥好展示的");
}
for (int i = front; i < front + size(); i++) {
System.out.printf("打印第几位arr[%d]内容为%d", (i) % maxSize, arr[(i) % maxSize]);
System.out.print("\n");
}
}
public int size() {
// (0 - 2 + 3) % 3
// (2 - 0 + 3) % 3
return (rear - front + maxSize) % maxSize;
}
public int headQueue() {
return arr[front];
}
}
个人理解:我本来以为队列的先进先出后进后出,是当前一个数据出去之后,后面的数据会整体向前移动,然后把最后一位置空(就像在 ArrayQueue.java
我注释的那小段代码)
但是实际上是通过不断修改队列的起始位置和结束位置,不断的改变数组中的有效区域实现的代码中多次出现的%
是为了让起始位置和结束位置超出数组的最大范围后从头开始,
创建一个4
位的数组的话那么队列的最大容量就是(4-1)
,因为队列最大的结束位置是为数组的最后一位,所有要预留一位,不然无法判断队列在数据中的有效数据
结束位置是不包含队列元素的,起始位置有队列元素