数据结构分类
-
线性结构: 数据元素一对一的线性关系。
-
顺序存储结构(数组:存储元素内存连续)和 链式存储结构(链表:地址指向下一个)
-
数组,链表,队列,栈
-
-
非线性结构
二维数组,多维数组,广义表,树,图
1. 稀疏数组/队列
1.1 稀疏数组
android.util包下的SparseArray
- 用来替换
HashMap
- 底层是两条数组,一组存放
key
,一组存放value
- key值只能为int 类型
- 优点
- 频繁的插入删除操作效率高(延迟删除机制保证了效率)
- 会定期通过gc函数来清理内存,内存利用率高
- 缺点
- 二分查找的时间复杂度O(log n),大数据量的情况下,效率没有HashMap高
- key只能是int 或者long
需求:五子棋程序中,有存盘退出和续上盘的功能。
**分析:**如果使用二维数组,0:代表空,1:代表黑棋,2:代表白棋。
- 缺点:记录0 没有意义,引入稀疏数组概念。
- 稀疏数组处理:
- 二维数组
- 第一个代表下标(棋盘0,其他值1…);第二个:0,1,2分别代表x坐标,y坐标,值(棋盘值和黑棋1或者白棋2)
//0: 表示没有棋子, 1:黑子 2:白
int[][] chessArr = new int[11][11];
chessArr[1][2] = 1;
chessArr[2][3] = 2;
chessArr[4][5] = 2;
System.out.println("原始的二维数组~~");
for (int[] row : chessArr) {
for (int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
// 将二维数组 转 稀疏数组的
int sum = 0;
for (int[] ints : chessArr) {
for (int j = 0; j < ints.length; j++) {
if (ints[j] != 0) {
sum++;
}
}
}
//棋盘元素数据 + 棋子元素数据
int[][] sparseArr = new int[sum + 1][3];
sparseArr[0][0] = chessArr.length;
sparseArr[0][1] = chessArr[0].length;
sparseArr[0][2] = sum;
int count = 0;
for (int i = 0; i < chessArr.length; i++) {
for (int j = 0; j < chessArr[i].length; j++) {
if (chessArr[i][j] != 0) {
count++;
sparseArr[count][0] = i;
sparseArr[count][1] = j;
sparseArr[count][2] = chessArr[i][j];
}
}
}
// 输出稀疏数组的形式
System.out.println();
System.out.println("得到稀疏数组为~~~~");
for (int i = 0; i < sparseArr.length; i++) {
System.out.printf("%d\t%d\t%d\t\n",
sparseArr[i][0], sparseArr[i][1], sparseArr[i][2]);
}
System.out.println();
//恢复含0棋盘数组
int[][] chessArr2 = new int[sparseArr[0][0]][sparseArr[0][1]];
for (int i = 1; i < sparseArr.length; i++) {
chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
}
System.out.println();
System.out.println("恢复后的二维数组");
for (int[] row : chessArr2) {
for (int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
1.2 队列
概念
- 有序列表,可用数组或者链表实现。
- 先进先出。
队列实现
- 定义3个值
- front:起始下标
- rear:终点下标
- maxSize:队列大小
- front == rear 时,队列为空
- rear == maxSize - 1时,队列满
- 入队操作(addQueue)
- 尾指针后移一位:rear+1
- 当rear == maxSize - 1: 无法加入队。
- 出队操作(getQueue)
- front后移一位:front + 1
- 当front+1 == rear:没有数据出队
public class ArrayQueue {
/**
* 队列容量
*/
private int maxSize;
/**
* 头位置
*/
private int front;
/**
* 尾位置
*/
private int rear;
/**
* 存放数据
*/
private int[] arr;
public ArrayQueue(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
front = -1;
rear = -1;
}
public boolean isFull() {
return rear == maxSize - 1;
}
public boolean isEmpty() {
return front == rear;
}
/**
* 入队
*
* @param n
*/
public void addQueue(int n) {
if (isFull()) {
System.out.println("queue is full");
return;
}
rear++;
arr[rear] = n;
}
/**
* 出队
*
* @return
*/
public int getQueue() {
if (isEmpty()) {
throw new RuntimeException("queue is empty!");
}
front++;
int v = arr[front];
arr[front] = 0;
return v;
}
/**
* 查询队列
*/
public void showQueue() {
if (isEmpty()) {
System.out.println("queue is empty!");
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.printf("arr[%d]=%d\n", i, arr[i]);
}
}
/**
* 获取队列头
*
* @return
*/
public int headQueue() {
if (isEmpty()) {
throw new RuntimeException("queue is empty!");
}
return arr[front+1];
}
public static void main(String[] args) {
ArrayQueue queue = new ArrayQueue(3);
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): 查看队列头的数据");
char key = scanner.next().charAt(0);
switch (key) {
case 's':
queue.showQueue();
break;
case 'e':
scanner.close();
loop = false;
break;
case 'a':
System.out.println("输出一个数");
int n = scanner.nextInt();
queue.addQueue(n);
break;
case 'g':
int v = queue.getQueue();
System.out.printf("值:%d\n", v);
break;
case 'h':
int h = queue.headQueue();
System.out.printf("值head:%d\n", h);
break;
default:
break;
}
}
System.out.println("程序退出~~");
}
}
1.3 循环队列
针对:1.2中队列不能循环使用,引出循环队列。
实现分析
- 对环状队列,进行取模运算:%
- 重点:空出最后一个位置,作为队尾标识。
- 队空:rear == front
- 队满:(rear + 1) % maxSize == front
- 队中数据:(rear + maxSize - front) % maxSize (如果rear = 1, front = 2 。需要rear+maxSize)
- 入队(重要):当前rear存值后,rear++ 后移一位(空标识)
public class CircleQueue {
/**
* 队列容量
*/
private int maxSize;
/**
* 头位置
*/
private int front;
/**
* 尾位置
*/
private int rear;
/**
* 存放数据
*/
private int[] arr;
public CircleQueue(int maxSize) {
this.maxSize = maxSize;
arr = new int[maxSize];
front = 0;
rear = 0;
}
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
public boolean isEmpty() {
return front == rear;
}
/**
* 入队
*
* @param n
*/
public void addQueue(int n) {
if (isFull()) {
System.out.println("queue is full");
return;
}
arr[rear] = n;
//空标识后移,空标识下标如果超过容量值
rear = (rear + 1) % maxSize;
}
/**
* 出队
*
* @return
*/
public int getQueue() {
if (isEmpty()) {
throw new RuntimeException("queue is empty!");
}
//第一个元素
int value = arr[front];
front = (front + 1) % maxSize;
return value;
}
/**
* 查询队列
*/
public void showQueue() {
if (isEmpty()) {
System.out.println("queue is empty!");
return;
}
for (int i = front; i < front + size(); i++) {
System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
}
}
/**
* 当前队列数量
*
* @return
*/
public int size() {
return (rear - front + maxSize) % maxSize;
}
/**
* 获取队列头
*
* @return
*/
public int headQueue() {
if (isEmpty()) {
throw new RuntimeException("queue is empty!");
}
return arr[front];
}
public static void main(String[] args) {
//尾部空标识占位一个,有效最大值3
CircleQueue queue = new CircleQueue(4);
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): 查看队列头的数据");
char key = scanner.next().charAt(0);
switch (key) {
case 's':
queue.showQueue();
break;
case 'e':
scanner.close();
loop = false;
break;
case 'a':
System.out.println("输出一个数");
int n = scanner.nextInt();
queue.addQueue(n);
break;
case 'g':
int v = queue.getQueue();
System.out.printf("值:%d\n", v);
break;
case 'h':
int h = queue.headQueue();
System.out.printf("值head:%d\n", h);
break;
default:
break;
}
}
}
}