1. 冒泡排序
冒泡排序(Bubble Sort)是一种基础的排序算法,其核心原理是反复遍历待排序序列,比较相邻元素并交换位置,直到整个序列有序。这种算法得名于元素如同气泡般,通过交换逐渐 “浮” 到正确的位置。
算法步骤
- 比较相邻元素:从序列头部开始,比较每对相邻元素。若顺序错误(如升序中前一个元素大于后一个),则交换它们。
- 重复遍历:对每一对相邻元素重复上述步骤,直到最后一对。
- 减少遍历范围:每轮遍历后,最大(或最小)的元素会 “冒泡” 到末尾,因此下一轮遍历可忽略已排序的元素。
- 终止条件:当某轮遍历中未发生任何交换时,说明序列已完全有序,算法终止。
示例过程
以数组 [5, 3, 8, 4, 6] 升序排序为例:
- 第一轮:
比较 5 和 3,交换 → [3, 5, 8, 4, 6]
比较 5 和 8,不交换 → [3, 5, 8, 4, 6]
比较 8 和 4,交换 → [3, 5, 4, 8, 6]
比较 8 和 6,交换 → [3, 5, 4, 6, 8]
结果:最大元素 8 移至末尾。 - 第二轮:
比较 3 和 5,不交换 → [3, 5, 4, 6, 8]
比较 5 和 4,交换 → [3, 4, 5, 6, 8]
比较 5 和 6,不交换 → [3, 4, 5, 6, 8]
结果:次大元素 6 移至倒数第二位置。 - 第三轮:
比较 3 和 4,不交换 → [3, 4, 5, 6, 8]
比较 4 和 5,不交换 → [3, 4, 5, 6, 8]
结果:序列已有序,但算法需再进行一轮确认。
第四轮:未发生交换,算法终止。
时间复杂度
- 最坏情况:
O(n的平方)(数组完全逆序)。 - 最好情况:
O(n)(数组已有序,添加交换标记后)。
空间复杂度
O(1)(仅需常数级额外空间)。
public static void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
// 每次把最大的数放到最右边
if (arr[j] > arr[j + 1]) {
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
注意:j < arr.length-i-1 , 是-1不是+1, 不然会数组下标越界。
2. 二分法查找
前提:数据必须有序
要求:查找指定的值在有序的数组中,返回对应数组元素下标。
算法:用当前元素与中间大小元素比较,若小于,则取左边子数组的中间元素做比较。
public static int binarySearch(int[] arr, int key) {
int start = 0;
int end = arr.length - 1;
if (key < arr[start] || key > arr[end]) {
return -1;
}
while (start <= end) {
int middle = (start + end) / 2;
if (key == arr[middle]) {
return middle;
} else if (key > arr[middle]) {
start = middle + 1;
} else {
end = middle - 1;
}
}
return -1;
}
注意:
- while (start <= end) , 注意<=不是<
- 注意不要把arr[index]和下标index搞混。
3. 快速排序(高频考题)
快速排序的原理:选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的)。一般选择序列的第一个元素作为基准值。
public class QuickSort {
public static int getBase(int[] arr, int low, int high) {
int base = arr[low];
while (low < high) {
// 从右边数,找到比基准元素小的元素
while (low < high && base <= arr[high]) {
high--;
}
arr[low] = arr[high];
// 从左边数,找到比基准元素大的元素
while (low < high && arr[low] <= base) {
low++;
}
arr[high] = arr[low];
}
// 把基数元素base放到当前位置,并返回当前位置
arr[low] = base;
return low;
}
public static void sort(int[] arr, int low, int high) {
if (low < high) {
int base = getBase(arr, low, high);
sort(arr, low, base);
sort(arr, base + 1, high);
}
}
public static void main(String[] args) {
int arr[] = { 49, 38, 65, 97, 76, 13, 27, 49, 78, 34, 12, 64, 5, 4, 62, 99, 98, 54, 56, 17, 18, 23, 34, 15, 35,
25, 53, 51 };
sort(arr, 0, arr.length - 1);
for (int e : arr) {
System.out.print(e + " ");
}
}
}
注意:1. getBase和sort的入参都是int[] arr, int low, int high
2. sort时,不要忘记放在if(low<high){…}中。
3. getBase时,规律性较强,记住在while(low<high){} 外层外面先int base = arr[low]; 而在while{}结束时正相反:arr[low]=base; 再return low;
4. while(low<high && base<=arr[high]) 时注意是<=而不是<
5. 最后调用sort时:
int base = getBase(arr, low, high);
sort(arr, low, base);
sort(arr, base+1, high);
注意最后是base+1而不是base。
4. 二叉树逐层打印
import java.util.LinkedList;
import java.util.Queue;
public class cengci {
public static void print(BinaryTree root) {
Queue<BinaryTree> queue = new LinkedList<>();
queue.add(root);
BinaryTree currentLineLastNode = null;
BinaryTree last = root;
while(queue.size() > 0) {
BinaryTree currentNode = queue.poll();
if (currentNode.hasLeftNode()) {
queue.add(currentNode.getLeftNode());
currentLineLastNode = currentNode.getLeftNode();
}
if (currentNode.hasRightNode()) {
queue.add(currentNode.getRightNode());
currentLineLastNode = currentNode.getRightNode();
}
System.out.print(" " + currentNode.getValue());
if (last.equals(currentNode)) {
System.out.println();
last = currentLineLastNode;
}
}
}
public static void main(String[] args) {
BinaryTree root = new BinaryTree();
root.setValue("root");
BinaryTree left01 = new BinaryTree("left01");
BinaryTree right01 = new BinaryTree("right01");
root.setLeftNode(left01);
root.setRightNode(right01);
BinaryTree left11 = new BinaryTree("left11");
BinaryTree right11 = new BinaryTree("right11");
left01.setLeftNode(left11);
left01.setRightNode(right11);
BinaryTree left12 = new BinaryTree("left12");
BinaryTree right12 = new BinaryTree("right12");
right01.setLeftNode(left12);
right01.setRightNode(right12);
print(root);
}
}