1 简单介绍
我们所说的数据结构主要是指数据在内存中的存储结构,即程序运行时,我们通过将数据存入不同的容器,通过操作容器内的数据,以完成我们的业务逻辑。
数据结构在物理结构上一般分为顺序结构和链式结构。
所有的数据结构,本质是不是顺序结构就是链式结构,要么就是复合结构。
- 顺序结构(在内存中是连续的地址空间)
- 链式结构(在内存中是非连续的地址空间,通过存储下一个数据的地址指针(Java中就是对象变量)找到下一个数据)
数据结构的逻辑结构,也是我们数据结构系列文章的讲解顺序,下面我仅列出大纲
线性结构
- 数组
- 链表
- 栈
- 队列
树
- 二叉树
- 非二叉树
- 图
复合数据结构
- 哈希表
- 跳表
- 线段树
2 数组
数组是顺序结构的代表,也是线性结构的代表,也是日常我们最常使用的一种数据结构,Java中的ArrayList就是对数组的一种封装,使其可以动态扩容,更方便的增删改查。
访问的时间复杂度(O(1)通过下标访问,但往往需要结合搜索)
搜索的时间复杂度(O(n)可以通过二分查找优化O(logn))
插入的时间复杂度(O(n)需要移动其他元素)
删除的时间复杂度(O(n)需要移动其他元素)
特点:访问效率高,插入修改效率低,可能需要开辟比较大的连续存储空间
3 链表
链表是链式结构的代表,也是一种线性结构,Java中的LinkedList就是对链表的一种封装。
访问的时间复杂度(O(n)通过遍历访问)
搜索的时间复杂度(O(n))
插入的时间复杂度(O(1)需要修改地址指针即可)
删除的时间复杂度(O(1)需要修改地址指针即可)
特点:插入修改效率高,访问效率低,不需要连续存储空间,但是需要每个节点存放地址值,会浪费一部分空间
链表有如下几种形态
3.1 单链表
特点:访问只能向后访问,如果我们想要获取上一个节点必须再次遍历
3.2 双向链表
特点:弥补了单链表的一些不足,即可向前访问也可以向后访问,占用存储资源也更多,需要每个节点存储两个地址值
3.3 环(单向环和双向环)【严格说不属于线性结构】
特点:首尾闭合,可以用来解决一些比较有特点的问题,约瑟夫环,丢手帕问题
4 栈
栈的特点是先入后出,后入先出,也是非常经典的一种数据结构。
访问的时间复杂度(O(1)只能访问栈顶元素)
搜索的时间复杂度(O(n))
插入的时间复杂度(O(1)操作栈顶元素)
删除的时间复杂度(O(1)操作栈顶元素)
栈只有一个出入口,就像水桶一样,后进先出
Java的代码的执行原理就是借助栈来实现的,有些计算器也是基于栈来实现的
LeetCode第20题也可以巧妙的用栈来解决
package com.zhj.leetcode;
import java.util.Stack;
/**
* 力扣 20 是否是合法括号
* @author zhj
*/
public class Test20 {
public static void main(String[] args) {
String s = "()(){}[]{}";
System.out.println(isT(s));
}
public static boolean isT(String s) {
char[] chars = s.toCharArray();
Stack<Character> stack = new Stack<>();
for (int i = 0; i < chars.length; i++) {
if (chars[i] == '(' || chars[i] == '[' || chars[i] == '{') {
stack.push(chars[i]);
} else {
if (stack.size() == 0) {
return false;
} else {
Character pop = stack.pop();
if (chars[i] == ')') {
if (pop != '(') {
return false;
}
} else if (chars[i] == ']') {
if (pop != '[') {
return false;
}
} else if (chars[i] == '}') {
if (pop != '{') {
return false;
}
} else {
return false;
}
}
}
}
return true;
}
}
5 队列
队列与栈恰恰相反,队列是先进先出,两端开放(单端队列:一进一出;双端队列:两进两出)
访问的时间复杂度(O(n))
搜索的时间复杂度(O(n))
插入的时间复杂度(O(1))
删除的时间复杂度(O(1))
队列可以解决好多问题,比如上说控制超时时间删除LeetCode933
package com.zhj.leetcode;
import java.util.LinkedList;
import java.util.Queue;
/**
* 力扣933 队列计数器
* @author zhj
*/
public class Test933 {
public static void main(String[] args) {
RecentCounter rc = new RecentCounter();
System.out.println(rc.ping(1));
System.out.println(rc.ping(100));
System.out.println(rc.ping(3001));
System.out.println(rc.ping(3002));
}
}
class RecentCounter {
private Queue<Integer> queue;
public RecentCounter() {
queue = new LinkedList<>();
}
int ping(int t) {
queue.add(t);
// 计算符合3000毫秒以上出队列
while (!queue.isEmpty() && t - queue.peek() > 3000) {
queue.poll();
}
return queue.size();
}
}