水文:数据结构小记
未完,明天继续更。
参考
GeeksforGeeks: https://www.geeksforgeeks.org/data-structures/
一)数据结构类型
图片来源(GeeksforGeeks)
- 数组,array
- 链表,link
- 栈,stack
- 队列,queue
- 树,tree
- 哈希表,hash
- 堆,heap
- 图,graph
二)存储结构
逻辑结构
- 集合结构
- 线性结构
- 树形结构
- 图形结构
物理结构
- 顺序存储结构:相邻元素地址相邻
- 链式存储结构:相邻元素通过指针相连
三)note
1. 数组:顺序表
表有一个size属性,记录当前存储元素的个数;
表有一个capacity属性,记录当前表的容量;
- 空:size == 0
- 满:size == capacity
- 长度:size
- 扩容:size == capacity时,发生的行为。数组申请一个更大的空间,将原来的数据复制到新空间
- 基本操作:非尾端增删,会发生数据移动;get操作直接通过计算地址获取指定位置元素,比较快
2. 链表
节点:Node { next; data }
表由节点Node,通过Node的next指针域相连接;
表有一个head,代表链表的头,初始化为 head = new Node,其next为null,表明当前表没有元素
表有一个size属性,记录当前存储元素的个数;
- 空:size == 0.或head.next为null
- 长度:size.或从head.next开始计数,data域不为空则加1,然后判断下一个
- 基本操作:非头节点处增删,需要从head移动到指定索引节点处;get操作需要从head开始移动,较慢
3. 栈
栈是只支持在一端(称为栈顶)进行添加、删除操作的表;
初始状态:top = 0。按照size来理解即可;
- 支持操作:进栈、出栈、取栈顶元素
4. 队列
队列是只支持在一端进、另一端出操作的表;
尾进,头出;
- 类型:普通队列,循环队列,优先级队列(基于堆)
建议使用:链表队列、循环队列
1. 普通队列(数组实现):front = rear = 0
进,rear后移;出,front后移。
front前面的元素如何使用?
方法一:数组移动,效率太低;
方法二:循环数组,建议。
方法三:改用链表实现
2. 循环数组:front = rear = 0
空间可以充分利用,如何判断满和空?
方法一:count记录队列元素个数。空count==0,满count==size
方法二:数组空出一个位置,标记队列是否已满。空rear==front,满(rear+1)%SIZE==front
5. 树
存储:双亲表示法;孩子表示法;孩子兄弟表示法
类型:树、二叉树、线索二叉树、哈夫曼树
平衡二叉树:AVL、红黑树
多路平衡树:B树、B+树、B*树
Trie树:字典树。
字符串的公共前缀。
常见算法:层次遍历;前中后序遍历;树 森林 二叉树的转换算法
// 数组
class TreeNode<E> {
int leftIndex;
int rightIndex;
E value;
}
// 链表
class TreeNode<E> {
TreeNode<E> left;
TreeNode<E> right;
E value;
}
6. 哈希表
7. 图
存储:邻接矩阵;邻接表
类型:有向图、无向图
常见算法:
- 遍历算法:广度优先遍历 BFS、深度优先遍历 DFS
- 最小生成树算法:普利姆算法 Prime、克鲁斯卡尔算法 Kruskal
- 最短路径算法:迪杰斯特拉算法 Dijkstra、弗洛伊德算法 Floyd
- 拓扑排序
- 关键路径
四)查找和排序
查找算法
- 顺序表查找
- 有序表查找:折半查找、插值查找、斐波那契查找
- 线性索引查找:稠密索引、分块索引、倒排索引
- 二叉排序树
- 平衡二叉树:AVL
- 多路查找树:B树、B+树
- 散列表查找
排序算法:内排序
- 冒泡排序
- 简单选择排序
- 直接插入排序
- 希尔排序
- 堆排序
- 归并排序
- 快速排序
code
interface MyList<E> {
void add(E e);
void add(int index, E e);
E delete(int index);
E update(int index, E value);
E get(int index);
}
class MyArrayList<E> implements MyList<E> {
private E[] element;
private int size;
private void grow() {
// TODO 扩容
}
/*
1. size检查
2. 添加
3. 更新size
*/
public void add(E e) {
if (size == element.length) {
grow();
}
element[size++] = e;
}
/* 在index前面,增加E e。index取值范围:[0, size]
1.
*/
public void add(int index, E e) {
if (index < 0 || index > size) {
return;
}
if (size == element.length) {
grow();
}
int moved = size - index - 1;
if (moved > 0) {
System.arraycopy(element, index, element, index + 1, moved);
}
element[index] = e;
size++;
}
/*
1. 范围检查
2. 删除并移动
3. 更新size
3. 返回index old值
*/
public E delete(int index) {
if (index < 0 || index >= size) {
return null;
}
E result = element[index];
int moved = size - index - 1;
if (moved > 0) {
System.arraycopy(element, index + 1, element, index, moved);
}
element[--size] = null;
return result;
}
/*
1. 范围检查
2. 更新
3. 返回index old值
*/
public E update(int index, E value) {
if (index < 0 || index >= size) {
return null;
}
E result = element[index];
element[index] = value;
return result;
}
public E get(int index) {
if (index < 0 || index >= size) {
return null;
}
return element[index];
}
}
class MyLinkedList<E> implements MyList<E> {
static class Node<E> {
E data;
Node<E> next;
public Node() {}
public Node(E data) {
this(data, null);
}
public Node(E data, Node<E> next) {
this.data = data;
this.next = next;
}
}
private Node<E> head;
private int size;
// 头插法
public void add(E e) {
if (head == null) {
head = new Node<E>();
}
Node<E> node = new Node<E>(e, head.next);
head.next = node;
size++;
}
public void add(int index, E e) {
// TODO
}
public E delete(int index) {
if (head == null || index < 0 || index >= size) {
return null;
}
Node<E> next = head;
Node<E> p = head.next;
while (p != null && index > 0) {
next = p;
p = p.next;
index--;
}
E result = null;
if (p != null) {
result = p.data;
next.next = p.next;
p = null;
}
size--;
return result;
}
public E update(int index, E value) {
if (head == null || index < 0 || index >= size) {
return null;
}
Node<E> p = head.next;
while (p != null && index > 0) {
p = p.next;
index--;
}
E result = null;
if (p != null) {
result = p.data;
p.data = value;
}
return result;
}
public E get(int index) {
if (head == null || index < 0 || index >= size) {
return null;
}
Node<E> p = head.next;
while (p != null && index > 0) {
p = p.next;
index--;
}
return p != null ? p.data : null;
}
}
interface Stack<E> {
void push(E e);
void pop();
E top();
}
class MyArrayStack<E> implements Stack<E> {
private E[] element;
private int top = -1;
public void push(E e) {
if (top == element.length - 1) {
return;
}
element[++top] = e;
}
public void pop() {
if (top == -1) {
return;
}
element[top--] = null;
}
public E top() {
if (top == -1) {
return null;
}
return element[top];
}
}
interface Queue<E> {
boolean offer(E e);
boolean poll();
E peek();
}
class MyArrayQueue<E> implements Queue<E> {
private E[] element;
private int head;
private int tail;
/*
初始,队列head=tail=0
空: head == tail
满:(tail + 1) % element.length == head
入队:tail + 1
出队:head - 1
tail,所在位置无值
*/
public boolean offer(E e) {
if ((tail + 1) % element.length == head) {
return false;
}
element[tail] = e;
tail = (tail + 1) % element.length;
return true;
}
public boolean poll() {
if (head == tail) {
return false;
}
element[head] = null;
head = (head + 1) % element.length;
return true;
}
public E peek() {
if (head == tail) {
return null;
}
return element[head];
}
}