常用数据结构笔记

持续更新中...

Posted by CoderLeonidas on September 22, 2018

常用数据结构笔记


什么是数据结构

数据结构是计算机存储数据、组织数据的方式。

数据结构类型大致可以分为:

  • 线性结构: 常见的有: 线性表(数组、队列、链表、栈、哈希表等)
  • 树形结构: 常见的有: 二叉树、红黑树、AVL树、B树、堆、Trie、哈夫曼树、并查集等
  • 图形结构: 常见的有: 邻接矩阵、邻接表等

线性数据结构

线性表: 线性表是具有n个相同类型元素的有限序列(n>=0)

  • a1是首节点,an是尾节点
  • a1是a2的前驱,a2是a1的后继

数组

数组是一种顺序存储的线性表,所有元素的内存地址是连续的

1
	int [] array = new int[]{11,22,33};

数组的缺点: 容量固定,无法动态修改数组的容量;这个时候就需要用到动态数组

动态数组(ArrayList)

动态数组的接口设计:

1
2
3
4
5
6
7
8
9
10
11
int size();// 元素的数量
boolean isEmpty();// 数组是否为空
boolean containis(E element);// 是否包含某个元素
void add(E element);// 添加元素到最后面
E get(int index);// 获取index位置对应的元素
E set(int index, E element);// 设置index位置对应的元素
void add(int index, E element);// 在index位置添加元素
E remove(int index);// 删除index位置对应的元素
int indexof(E element);// 查看元素的位置
void clear();// 清除所有元素

动态数组的缺点:

  1. 创建时有一个初始的内存空间,当添加新元素且内存空间不够时,会开辟一个当前数组内存空间大小的新空间。这样就会造成内存空间的大量浪费。可以通过链表来解决这一问题。
  2. 动态数组在尾部添加元素的复杂度是O(1), 在头部移除元素的复杂度是O(N).

链表(LinkedList)

链表是一种链式存储的线性表,所有元素的内存地址不一定是连续的。

链表的接口设计:

  • 链表自身必须有2个接口:
1
2
3
int size(); // 返回链表的长度(节点的数量)

E first();// 返回链表的头结点
  • 链表节点的接口设计:
1
2
3
E element; // 本节点存储的节点数据

E next;// 下一个节点(指针)
  • 单向链表
  • 双向链表
  • 循环链表
  • 静态链表

栈(Stack)

队列(Queue)

队列是一种特殊的线性表,只能在头尾两端进行操作 队尾(rear): 只能从队尾添加元素,一般叫做enQuene,入队 队头(front): 只能从队头移除元素,一般叫做deQueue,出队 原则: 先进先出(First in first out, FIFO)

队列的接口设计:

1
2
3
4
5
6
int size();// 元素的数量
boolean isEmpty(); // 队列是否为空
void enQueue(E element); // 入队,队尾添加元素
void deQueue();// 出队,从队头移除元素
E front();// 获取队列头元素
void clear(); // 清空队列

队列内部可以使用基础数据结构来实现: 动态数组、链表 优先使用双向链表,因为队列就是从头尾操作元素

  • 双端队列(Deque)
  • 循环队列

哈希表(HashTable)

哈希表也叫做散列表(hash有”剁碎“的意思) 哈希表通过哈希函数来实现高效处理数据

添加、搜索、删除数据的流程都类似:

  1. 利用哈希函数生成key对应的index,时间复杂度为O(1)
  2. 根据index操作定位数组元素,时间复杂度为O(1)

树形数据结构

二叉树(BinaryTree)

(☆)二叉搜索树(BinarySearchTree\BST)

二叉搜索树是二叉树的一种,是应用非常广泛的一种二叉树,英文简称BST,又被成为二叉查找树、二叉排序树

特点:

  • 任意一个节点的值都大于其左子树所有节点的值
  • 任意一个节点的值都小于其右子树所有节点的值
  • 它的左右子树也是一颗二叉搜索树

二叉搜索树可以大大提高搜索数据的效率 二叉搜索树存储的元素必须具备可比较性 比如int、double等; 对于自定义类型的节点,需要指定比较方式

不允许为nil

二叉搜索树的接口设计:

1
2
3
4
5
6
7
int size(); // 元素的数量
boolean isEmpty();// 是否为空
void clear();// 清除所有元素
void add(E element);// 添加元素
void remove(E element);// 移除元素
boolean contains(E element);//是否包含该元素

注意点: 二叉搜索树没有索引的概念,因为根本用不上

平衡二叉搜索树(BalancedBinarySearchTree\BBST)

  • AVL树(AVLTree)
  • (☆)红黑树(RedBlackTree)

    红黑树是一种自平衡的二叉搜索树,也可以叫做平衡二叉B树(Symmetric Binary B-tree)

红黑树必须满足以下5条性质:

  • 节点是Red或者Black
  • 根节点是Black
  • 叶子节点(外部节点,空节点,null节点)都是Black
  • Red节点的子节点都是Black

    Red节点的子节点都是Black

    从根节点到子节点的所有路径上不能有2个连续的Red节点

  • 从任意节点到叶子节点的所有路径都包含相同数量的Black节点

(☆)B树(B-Tree)

集合(TreeSet)

集合的特点:

  • 不存放重复的元素

  • 常用于去重

    • 存放新增的IP,统计新增IP量
    • 存放词汇,统计词汇量

集合的接口设计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Set<E> {
	int size();
	boolean isEmpty();
	void clear();
	boolean contains(E element);
	void add(E element);
	void remove(E element);
	void traversal(Visitor<E> visitor); // 遍历集合

	public static abstract class Visitor<E> {
		boolean stop;
		abstract boolean visit(E element);
	}
}

集合的内部实现可以利用: 动态数组 链表 二叉搜索树(AVL树、红黑树)

映射(TreeMap)

Map 在有些编程语言里也叫做字典(dictionary,比如Python、objective-c、Swift等) Map以key-value的形式存储数据 每个key都是唯一的

Map的接口设计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Map<K, V> {
	int size();
	boolean isEmpty();
	void clear();
	V put(K key, V value);
	V get(K key);
	V remove(K key);
	boolean containsKey(K key);
	boolean containsValue(V value);
	void  (Visitor<K, V> visitor);
	
	public static abstract class Visitor<K, V> {
		boolean stop;
		abstract boolean visit(K key, V value);
	}
}

哈夫曼树

(☆)Trie

线性+树形数据结构

集合(HashSet)

映射(HashMap、LinkedHashMap)

(☆)二叉堆(BinaryHeap)

优先级队列(PriorityQueue)