二分查找法
/**
* 二分查找
* @param array 源数组
* @param source 目标元素
* @return 如果找到则返回索引位置,找不到则返回-1
*/
public static int binarySearch(int[] array, int source) {
int start=0,end=array.length()-1,middle;
while(start<=end) {
middle=(start+end)>>>1;
if(array[middle] == source) return middle;
else if(array[middle] < source) start = middle + 1;
else if(array[middle] > source) end = middle - 1;
}
return -1;
}
冒泡排序
public static void bubbleSort(int arr[]) {
for (int i = 0; i < arr.length - 1; i++) {// 需要冒泡的次数
for (int j = 0; j < arr.length - 1 - i; j++) {// 循环比较
if (arr[j] > arr[j + 1]) {// 如果前面比后面大,则交换
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
插入排序
public static void insertionSort(int arr[]) {
for (int i = 1; i < arr.length; i++) {
//插入的数
int insertVal = arr[i];
//被插入的位置(准备和前一个数比较)
int index = i - 1;
//如果插入的数比被插入的数小
while (index >= 0 && insertVal < arr[index]) {
//将把 arr[index] 向后移动
arr[index + 1] = arr[index];
//让 index 向前移动
index--;
}
//把插入的数放入合适位置
arr[index + 1] = insertVal;
}
快速排序
/**
* 快速排序(无返回值)
* @param a 需要排序的数组
* @param low 数组的最小索引: 0
* @param high 数组的最大索引: arr.length - 1
*/
public static void quickSort(int[] a, int low, int high) {
int start = low;
int end = high;
int key = a[low];
while (end > start) {
//从后往前比较
while (end > start && a[end] >= key)
//如果没有比关键值小的,比较下一个,直到有比关键值小的交换位置,然后又从前往后比较
end--;
if (a[end] <= key) {
int temp = a[end];
a[end] = a[start];
a[start] = temp;
}
//从前往后比较
while (end > start && a[start] <= key)
//如果没有比关键值大的,比较下一个,直到有比关键值大的交换位置
start++;
if (a[start] >= key) {
int temp = a[start];
a[start] = a[end];
a[end] = temp;
}
//此时第一次循环比较结束,关键值的位置已经确定了。左边的值都比关键值小,右边的值都比关键值大,但是两边的顺序还有可能是不一样的,进行下面的递归调用
}
//递归
if (start > low) quickSort2(a, low, start - 1);//左边序列。第一个索引位置到关键值索引-1
if (end < high) quickSort2(a, end + 1, high);//右边序列。从关键值索引+1 到最后一个
}
二叉树的遍历
树的结构
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
}
前序遍历
他的访问顺序是:根节点→左子树→右子树
public static void preOrder(TreeNode tree) {
if (tree == null)
return;
System.out.printf(tree.val + "");
preOrder(tree.left);
preOrder(tree.right);
}
中序遍历
他的访问顺序是:左子树→根节点→右子树
public static void inOrderTraversal(TreeNode node) {
if (node == null)
return;
inOrderTraversal(node.left);
System.out.println(node.val);
inOrderTraversal(node.right);
}
后续遍历
他的访问顺序是:左子树→右子树→根节点
public static void postOrder(TreeNode tree) {
if (tree == null)
return;
postOrder(tree.left);
postOrder(tree.right);
System.out.println(tree.val);
}
BFS(宽度优先搜索(又称广度优先搜索))
他的访问顺序是:先访问上一层,在访问下一层,一层一层的往下访问
public static void levelOrder(TreeNode tree) {
if (tree == null)
return;
LinkedList<TreeNode> list = new LinkedList<>();//链表,这里我们可以把它看做队列
list.add(tree);//相当于把数据加入到队列尾部
while (!list.isEmpty()) {
TreeNode node = list.poll();//poll方法相当于移除队列头部的元素
System.out.println(node.val);
if (node.left != null)
list.add(node.left);
if (node.right != null)
list.add(node.right);
}
}
DFS(深度优先搜索)
他的访问顺序是:先访根节点,然后左结点,一直往下,直到最左结点没有子节点的时候然后往上退一步到父节点,然后父节点的右子节点在重复上面步骤……
public static void treeDFS(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
stack.add(root);
while (!stack.empty()) {
TreeNode node = stack.pop();
System.out.println(node.val);
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
}
递归写法(相等于前序遍历树)
public static void treeDFS(TreeNode root) {
if (root == null)
return;
System.out.println(root.val);
treeDFS(root.left);
treeDFS(root.right);
}
红黑树
红黑树的特性:
- 每个节点或者是黑色,或者是红色。
- 根节点是黑色。
- 每个叶子节点是黑色。 (注意:这里叶子节点,是指为空的叶子节点)
- 如果一个节点是红色的,则它的子节点必须是黑色的。
- 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
红黑树的基本操作:
红黑树的基本操作是添加、删除和旋转。在对红黑树进行添加或删除后,会用到旋转方法。因为添加或删除红黑树中的节点之后,红黑树会发生变化,可能不满足红黑树的5条性质,也就不再是一颗红黑树了。而通过旋转,可以使这颗树重新成为红黑树。简单点说,旋转的目的是让树保持红黑树的特性。
旋转包括两种:左旋 和 右旋。
从上图旋转的结果可以用如下代码实现:
/**
* 左旋
* */
private TreeNode leftRotate(TreeNode x) {
TreeNode y = x.right;
// 左旋转
x.right= y.left;// x的右边是β
y.left = x;// y的左边是x
y.color = x.color;// 变换颜色
x.color = RED;
return y;
}
/**
* 右旋
* */
private TreeNode rightRotate(TreeNode y) {
TreeNode x = y.left;
// 右旋转
y.left = x.right;// y的左边是β
x.right = y;// x的右边是y
x.color = y.color;// 变换颜色
y.color = RED;
return x;
}