• 数据结构:计算机存储、组织数据的方式
  • 数据库 CRUD 操作:增加(Create)、读取查询(Retrieve)、更新(Update)、删除(Delete)

数组(Array)

  • 擅长做查询和修改,不擅长做增加(可能需要扩容)和删除(移位)
  • 在随机访问时性能最好
  1. // 基于数组的线性表(集合)
  2. public class MyArrayList {
  3. private Object[] elementData;
  4. private int size;
  5. private static final int DEFAULT_CAPACITY = 10;
  6. public MyArrayList() {
  7. this(DEFAULT_CAPACITY);
  8. }
  9. public MyArrayList(int initiallyCapacity) {
  10. if (initiallyCapacity < 0) {
  11. throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
  12. }
  13. elementData = new Object[initiallyCapacity];
  14. }
  15. }
  16. // 1. 在形参包含索引的方法内,检查传入的索引是否越界
  17. // 2. 写每个方法时,最后要判断该方法是否会改变 size 的值

链表(Linked List)

  • 擅长做增加和删除(头和尾),不擅长做查询和修改
  • 在执行插入、删除操作时有较好的性能
  • 单向链表、双向链表

    链表的结构
    图 1 链表的结构

  1. // 基于双向链表的线性表(集合)
  2. public class MyLinkedList {
  3. private Node first; // 链表的第一个节点
  4. private Node last; // 链表的最后一个节点
  5. private int size; // 节点的数量
  6. // 删除链表中第一次出现的元素 o
  7. public boolean removeFirstOccurrence(Object o) {
  8. Node currentNode = first;
  9. while (currentNode != null) {
  10. if (currentNode.ele.equals(o)) {
  11. // 删除节点
  12. if (currentNode == first) {
  13. currentNode.next.prev = null;
  14. first = currentNode.next;
  15. size--;
  16. return true;
  17. } else if (currentNode == last) {
  18. currentNode.prev.next = null;
  19. last = currentNode.prev;
  20. size--;
  21. return true;
  22. } else {
  23. currentNode.prev.next = currentNode.next;
  24. currentNode.next.prev = currentNode.prev;
  25. size--;
  26. return true;
  27. }
  28. }
  29. currentNode = currentNode.next;
  30. }
  31. return false;
  32. }
  33. // 返回链表的字符串表示形式
  34. public String toString() {
  35. if (size == 0) {
  36. return "[]";
  37. }
  38. Node currentNode = first;
  39. StringBuilder sb = new StringBuilder();
  40. sb.append("[");
  41. for (int i = 0; i < size; i++) {
  42. sb.append(currentNode.ele);
  43. if (i != size - 1) {
  44. sb.append(", ");
  45. } else {
  46. sb.append("]");
  47. }
  48. currentNode = currentNode.next;
  49. }
  50. return sb.toString();
  51. }
  52. // 内部类 Node
  53. private static class Node {
  54. Node prev; // 上一个节点
  55. Node next; // 下一个节点
  56. Object ele; // 节点中的数据
  57. Node(Object ele) {
  58. this.ele = ele;
  59. }
  60. }
  61. }
  62. // 1. 先修改当前节点,再修改当前节点的上一节点、当前节点的下一节点,最后修改链表的 first、last
  63. // 2. 写每个方法时,最后要判断该方法是否会改变 size 的值

栈(Stack)

  • 一种运算受限的线性表,仅允许在表的一端进行插入和删除运算
  • 后进先出(LIFO)
  • 进栈、入栈或压栈;出栈或退栈
  • 底层可以数组来存储,也可以使用链表来存储

队列(Queue)

  • 一种特殊的线性表,只允许在表的后端(rear)进行插入操作,在表的前端(front)进行删除操作
  • 单向队列(Queue):先进先出(FIFO),只能从队列尾插入数据,只能从队列头删除数据
  • 双向队列(Deque):可以从队列尾/头插入数据,也可以从队列头/尾删除数据

哈希表(Hash Table)

  • 元素的值和索引存在对应的关系的数组
  • 元素值 —> Hash 函数 —> 哈希码 —> 某种映射关系(压缩映射) —> 元素存储索引
  • 可以直接根据该元素的 hashCode 值计算出该元素的存储位置,因此具有很好的存取和査找性能

    哈希表
    图 2 哈希表

堆(Heap)

图(Graph)

树(Tree)

  • 适用于范围查找,一般用来做索引

    B+树
    图 3 B+树