字符串的顺序存储结构,是用一组地址连续的存储单元来存储串中的字符序列,一般是用定长数组来实现。有些语言会在串值后面加一个不计入串长度的结束标记符,比如 \0 来表示串值的终结。
字符串的链式存储结构,与线性表是相似的,但由于串结构的特殊性(结构中的每个元素数据都是一个字符),如果也简单地将每个链结点存储为一个字符,就会造成很大的空间浪费。因此,一个结点可以考虑存放多个字符,如果最后一个结点未被占满时,可以使用 "#" 或其他非串值字符补全。
每个结点设置字符数量的多少,与串的长度、可以占用的存储空间以及程序实现的功能相关。
除了在连接串与串操作时有一定的方便之外,不如顺序存储灵活,在性能方面也不如顺序存储结构好。
字符串的基本操作
新增操作
和数组非常相似,都牵涉对插入字符串之后字符的挪移操作,所以时间复杂度是 O(n)。
对于特殊的插入操作时间复杂度也可以降低为 O(1)。例如,在 s1 的最后插入 s2,也叫作字符串的连接。
删除操作
和数组同样非常相似,也可能会牵涉删除字符串后字符的挪移操作,所以时间复杂度是 O(n)。
对于特殊的删除操作时间复杂度也可以降低为 O(1)。例如,在 s1 的最后删除若干个字符,不牵涉任何字符的挪移。
查找操作
在字符串 A 中查找字符串 B,则 A 就是主串,B 就是模式串。
主串的长度记为 n,模式串长度记为 m,则n>m。
字符串匹配算法的时间复杂度就是 n 和 m 的函数。
子串查找(字符串匹配)
字符串匹配算法的案例
查找出两个字符串的最大公共字串
树和二叉树 树 -- Tree
树结构在存在“一对多”的数据关系中,可被高频使用,这也是它区别于链表系列数据结构的关键点。
树是由结点和边组成的,不存在环的一种数据结构。
树满足递归定义的特性。如果一个数据结构是树结构,那么剔除掉根结点后,得到的若干个子结构也是树,通常称作子树。
树的结点的层次从根结点算起,根为第一层,根的“孩子”为第二层,根的“孩子”的“孩子”为第三层,依此类推。
树中结点的最大层次数,就是这棵树的树深(称为深度,也称为高度)。
二叉树 -- Binary Tree 二叉树每个结点最多有两个子结点,分别称作左子结点和右子结点。 二叉树中两个特殊的类型
满二叉树,定义为除了叶子结点外,所有结点都有 2 个子结点。
完全二叉树,定义为除了最后一层以外,其他层的结点个数都达到最大,并且最后一层的叶子结点都靠左排列。它方便了顺序存储法的存储方式。
存储二叉树的两种办法
链式存储法,也就是像链表一样,每个结点有三个字段,一个存储数据,另外两个分别存放指向左右子结点的指针。
顺序存储法,就是按照规律把结点存放在数组里。
树的基本操作 遍历
前序遍历,对树中的任意结点来说,先打印这个结点,然后前序遍历它的左子树,最后前序遍历它的右子树。
public static void preOrderTraverse(Node node) {if (node == null)
return;
System.out.print(node.data + " ");
preOrderTraverse(node.left);
preOrderTraverse(node.right);
}
中序遍历,对树中的任意结点来说,先中序遍历它的左子树,然后打印这个结点,最后中序遍历它的右子树。
public static void inOrderTraverse(Node node) {if (node == null)
return;
inOrderTraverse(node.left);
System.out.print(node.data + " ");
inOrderTraverse(node.right);
}
后序遍历,对树中的任意结点来说,先后序遍历它的左子树,然后后序遍历它的右子树,最后打印它本身。
public static void postOrderTraverse(Node node) {if (node == null)
return;
postOrderTraverse(node.left);
postOrderTraverse(node.right);
System.out.print(node.data + " ");
} 二叉树的增删查操作很普通,时间复杂度与链表并没有太多差别 二叉查找树 -- Binary Search Tree, BST 特性
在二叉查找树中的任意一个结点,其左子树中的每个结点的值,都要小于这个结点的值。
在二叉查找树中的任意一个结点,其右子树中每个结点的值,都要大于这个结点的值。
在二叉查找树中,会尽可能规避两个结点数值相等的情况。