稀疏数组
(1)分析
例子:棋盘的存盘与续上局
将棋盘抽象成二维数组,元素为0表示此处无棋子,若为1则表示此处有棋子(当然,也可以再设2表示另一方的棋子),在下棋途中想要保存棋盘时,即将当前棋盘状态保存起来,方便下此导入,从而继续上局,为节省保存时的占用空间,可将棋盘二维数组压缩为稀疏数组,从而在外部持久化保存时,保存稀疏数组中的信息,再下次导入时,则将稀疏数组重新解析成二维数组,并生成上局的棋盘状态,即可完成棋盘。
(2)代码
package 稀疏数组;
public class Test {
public static void main(String[] args) {
// 1、创建 二维数组
int[][] chessTable = new int[10][10];
chessTable[0][2] = 1;
chessTable[3][5] = 1;
chessTable[5][8] = 1;
chessTable[8][9] = 1;
System.out.println("棋盘初始为----------");
showDeepArray(chessTable);
// 2、得到 稀疏矩阵
// 得到数组中有效值的个数,以便于决定稀疏矩阵的 行数 - 1 即为此值
int num = 0;
for (int[] row : chessTable) {
for (int col : row) {
if (col != 0) {
num++;
}
}
}
int[][] compressedChessTable = new int[num + 1][3];
compressedChessTable[0][0] = chessTable.length; // 棋盘行数
compressedChessTable[0][1] = chessTable[0].length; // 棋盘列数
compressedChessTable[0][2] = num; // 棋盘有效值个数
int count = 1;
for (int i = 0; i < chessTable.length; i++) {
for (int j = 0; j < chessTable[0].length; j++) {
if (chessTable[i][j] != 0) {
compressedChessTable[count][0] = i;
compressedChessTable[count][1] = j;
compressedChessTable[count][2] = chessTable[i][j];
count++;
}
}
}
System.out.println("稀疏矩阵为----------");
showDeepArray(compressedChessTable);
// 3、解析 稀疏矩阵 到新的 二维数组
int[][] newChessTable = new int[compressedChessTable[0][0]][compressedChessTable[0][1]];
for (int i = 1; i <= compressedChessTable[0][2]; i++) {
newChessTable[compressedChessTable[i][0]][compressedChessTable[i][1]] = compressedChessTable[i][2];
}
System.out.println("解析出的数组为----------");
showDeepArray(newChessTable);
}
public static void showDeepArray(int[][] deepArray) {
for (int[] row : deepArray) {
for (int col : row) {
System.out.printf("%d\t", col);
}
System.out.println();
}
}
}
(3)结果
循环队列
(1)分析
为避免顺序存储方式的队列实现中,队列的“假溢出”现象,为实现队列数组的循环复用,设计了循环队列,将队列头指针 front 指向队列的第一个元素下标,而队列尾指针 rear 指向队列最后一个元素的下一个位置下标,从而便于区分队列空和队列满这两种状态
队列空:front == rear
队列满:(rear + 1) % maxSize == front
队列长度:(rear - front + maxSize) % maxSize
(2)代码
package 循环队列;
import java.util.Scanner;
class CircleQueue {
private int maxSize; // 数组的最大容量
private int front; // 队列头,规定它指向队列的第一个元素下标
private int rear; // 队列尾,规定它指向队列最后一个元素的下一个位置的下标
private int[] data; // 存放数据
public CircleQueue(int maxSize) {
this.maxSize = maxSize;
data = new int[maxSize];
front = 0;
rear = 0;
}
// 判断队列是否满
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
// 判断队列是否空
public boolean isEmpty() {
return front == rear;
}
// 添加数据到队列
public void addQueue(int n) {
if (isFull()) {
throw new RuntimeException("队列满,不能添加数据~");
} else {
data[rear] = n;
rear = (rear + 1) % maxSize;
}
}
// 获取队列数据
public int getQueue() {
if (isEmpty()) {
throw new RuntimeException("队列空,不能取数据~");
} else {
int temp = data[front];
front = (front + 1) % maxSize;
return temp;
}
}
// 显示队列的所有数据
public void showQueue() {
if (isEmpty()) {
throw new RuntimeException("队列空,没有数据~");
}
int temp = front;
for (int i = 0; i < (rear - front + maxSize) % maxSize; i++) {
System.out.printf("%d\t", data[temp]);
temp = (temp + 1) % maxSize;
}
System.out.println();
}
}
public class Test {
public static void main(String[] args) {
CircleQueue queue = new CircleQueue(5);
char input = ' ';
Scanner scanner = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("-------------------------------------");
System.out.println("s(show) 显示队列");
System.out.println("e(exit) 退出程序");
System.out.println("a(add) 添加数据到队列");
System.out.println("g(get) 从队列中取出数据");
System.out.println("-------------------------------------");
input = scanner.next().charAt(0);
switch (input) {
case 's':
queue.showQueue();
break;
case 'e':
loop = false;
break;
case 'a':
System.out.print("请输入要添加的数据:");
int newNum = scanner.nextInt();
queue.addQueue(newNum);
break;
case 'g':
int num = queue.getQueue();
System.out.println("取出的数据为:" + num);
}
}
}
}
(3)结果
单链表
(1)分析
共有如下方法的实现
注意事项:
- 注意条件判断,例如单链表为空不能进行查找,删除,更新,等等操作
- 单链表反转时,若链表为空或只有一个结点,则不必反转
- 若欲将单链表中的结点加入到另一个单链表上,切记之前结点中的 next 属性中包含了其后的结点信息,我们应该”复制“一个之前的结点(除其 next 信息外的其他信息),从而可避免此问题
(2)代码
package 链表.单链表;
class StudentNode {
public int no;
public String name;
public StudentNode next;
public StudentNode(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "StudentNode{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
class StudentLinkedList {
StudentNode head = new StudentNode(0, "");
/**
* 普通插入,插入到末尾
* @param node 待插入结点
*/
public void add(StudentNode node) {
StudentNode temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = node;
System.out.println("添加成功~");
}
/**
* 按编号顺序插入
* @param node 待插入结点
*/
public void addByNo(StudentNode node) {
StudentNode pre = head;
if (pre.next == null) { // 链表为空
pre.next = node; // 直接将结点插入node.no
System.out.println("添加成功~");
return;
}
// 链表不为空
StudentNode temp = pre.next;
while (temp != null) {
if (node.no < temp.no) {
pre.next = node;
node.next = temp;
System.out.println("添加成功~");
return;
}
pre = pre.next;
temp = pre.next;
}
// temp 为null时,pre即为最后一个结点
pre.next = node;
}
/**
* 删除结点
* @param no
*/
public void deleteByNo(int no) {
StudentNode temp = head.next;
if (temp == null) { // 链表为空,则结束操作
System.out.println("链表为空,不可执行删除操作~");
return;
} else if (temp.no == no) { // 第一个结点即为待删除结点
head.next = temp.next;
return;
} else { // 待删除结点不是第一个结点
while (temp != null && temp.next != null) {
if (temp.next.no == no) {
temp.next = temp.next.next;
System.out.println("删除成功~");
return;
}
temp = temp.next;
}
System.out.println("未查找到~");
}
}
/**
* 更新结点
* @param node 更新后的结点
*/
public void update(StudentNode node) {
StudentNode temp = head.next;
while (temp != null) {
if (temp.no == node.no) {
temp.name = node.name;
System.out.println("修改成功~");
return;
}
temp = temp.next;
}
System.out.println("查无此人~");
}
/**
* 查找倒数第 k 个结点
* @param k
* @return
*/
public StudentNode getLastIndexNode(int k) {
// 首先得到链表长度,从而得知结点总个数
int len = getLength();
if (k > len || k < 0) { // 若k值过大
throw new RuntimeException("k值越界~");
}
// 需要遍历多少次
int count = len - k;
StudentNode temp = head.next;
for (int i = 0; i < count; i++) {
temp = temp.next;
}
return temp;
}
/**
* 单链表的逆序(打印)
* 方式一:从此链表中遍历取出结点,头插法插入一个新的链表中
*/
public void reverseLinkedList() {
// 如果当前链表为 空 或 只有一个结点 则无需反转
StudentNode temp = head;
if (temp.next == null || temp.next.next == null) {
return;
}
temp = temp.next; // 指向第一个结点
StudentNode tempHead = new StudentNode(0, "");
while (temp != null) {
StudentNode node = new StudentNode(temp.no, temp.name);
node.next = tempHead.next;
tempHead.next = node;
temp = temp.next;
}
head = tempHead;
}
/**
* 单链表的逆序(打印)
* 方式二:利用栈
*/
public void reverseLinkedList_ByStack() {
// 如果当前链表为 空 或 只有一个结点 则无需反转
StudentNode temp = head;
if (temp.next == null || temp.next.next == null) {
return;
}
Stack<StudentNode> stack = new Stack<>();
temp = head.next;
while (temp != null) {
stack.push(temp);
temp = temp.next;
}
while (stack.size() > 0) {
StudentNode node = stack.pop();
System.out.println(node);
}
}
/**
* 得到链表长度
* @return
*/
public int getLength() {
int num = 0;
StudentNode temp = head.next;
while (temp != null) {
num++;
temp = temp.next;
}
return num;
}
/**
* 展示链表中所有结点
*/
public void show() {
StudentNode temp = head.next;
if (temp == null) {
System.out.println("链表为空~");
}
while (temp != null) {
System.out.println(temp);
temp = temp.next;
}
}
}
public class Test {
public static void main(String[] args) {
StudentNode node1 = new StudentNode(2, "tom");
StudentNode node2 = new StudentNode(1, "mike");
StudentNode node3 = new StudentNode(3, "jhon");
StudentLinkedList linkedList = new StudentLinkedList();
linkedList.show();
System.out.println("----------------------------");
linkedList.addByNo(node1);
linkedList.addByNo(node2);
linkedList.addByNo(node3);
linkedList.show();
// 得到倒数第 2 个结点
int k = 2;
System.out.println("倒数第" + k + "个结点:" + linkedList.getLastIndexNode(k));
System.out.println("将链表反转=======");
linkedList.reverseLinkedList();
linkedList.show();
System.out.println("----------------------------");
linkedList.deleteByNo(2);
linkedList.show();
System.out.println("长度为:" + linkedList.getLength());
System.out.println("----------------------------");
linkedList.deleteByNo(1);
linkedList.show();
System.out.println("----------------------------");
linkedList.update(new StudentNode(3, "Jhon SiNa"));
linkedList.show();
}
}