一:引言
算法是计算机科学中至关重要的概念,它是解决问题的步骤和规则的集合。无论在哪个领域,算法都扮演着关键角色,并且广泛应用于各种计算任务中。
算法在现实生活中的应用非常广泛,例如:
搜索引擎:搜索引擎需要通过算法来确定搜索结果的相关性和排序。
路线规划:导航应用根据算法来计算最短路径或最优路线。
数据压缩:压缩算法可以减小数据的体积,提高存储和传输效率。
人工智能:机器学习和深度学习算法被用于图像识别、语音识别等任务。
程序员需要掌握算法的原因有以下几点:
解决问题:算法是编写高效、可靠的代码的基础。对于复杂的问题,正确选择和实现适当的算法是必不可少的。
提高性能:优化算法可以显著提高程序的执行效率和资源利用率。对于大规模数据处理、实时系统和并发编程等情况下,高效的算法尤为重要。
解决困难问题:有些问题是非常复杂和困难的,只有理解和应用正确的算法才能得到满意的解决方案。
探索新领域:算法是计算机科学领域的核心,掌握算法将使程序员能够更好地理解并探索新的技术领域。
二:常见算法介绍
排序算法
排序算法被广泛应用于各种场景中,如数据分析、数据库查询、图形渲染等。常见的排序算法包括:
1、冒泡排序(Bubble Sort)
public class BubbleSort {
public static void main(String[] args) {
int[] array = {5, 3, 8, 6, 2, 7, 1, 4};
System.out.println("排序前的数组:");
printArray(array);
bubbleSort(array);
System.out.println("\n排序后的数组:");
printArray(array);
}
// 冒泡排序算法
public static void bubbleSort(int[] array) {
int n = array.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (array[j] > array[j + 1]) {
// 交换相邻元素
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
// 打印数组元素
public static void printArray(int[] array) {
for (int num : array) {
System.out.print(num + " ");
}
System.out.println();
}
}
2、插入排序(Insertion Sort)
public class InsertionSort {
public static void insertionSort(int[] arr) {
int n = arr.length;
for (int i = 1; i < n; ++i) {
int key = arr[i];
int j = i - 1;
// 将比key大的元素向右移动
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
public static void main(String[] args) {
int[] arr = {5, 2, 8, 3, 1};
System.out.println("原始数组: ");
for (int num : arr) {
System.out.print(num + " ");
}
insertionSort(arr);
System.out.println("\n排序后的数组: ");
for (int num : arr) {
System.out.print(num + " ");
}
}
}
3、选择排序(Selection Sort)
public class SelectionSort {
public static void selectionSort(int[] array) {
int n = array.length;
for (int i = 0; i < n - 1; i++) {
int minIndex = i;
// 在未排序部分找到最小元素的索引
for (int j = i + 1; j < n; j++) {
if (array[j] < array[minIndex]) {
minIndex = j;
}
}
// 将最小元素与当前位置交换
int temp = array[minIndex];
array[minIndex] = array[i];
array[i] = temp;
}
}
public static void main(String[] args) {
int[] array = {64, 25, 12, 22, 11};
System.out.println("排序前:");
for (int num : array) {
System.out.print(num + " ");
}
selectionSort(array);
System.out.println("\n排序后:");
for (int num : array) {
System.out.print(num + " ");
}
}
}
4、快速排序(Quick Sort)
public class QuickSort {
public static void main(String[] args) {
int[] array = {5, 2, 9, 6, 1, 3, 8, 4, 7};
quickSort(array, 0, array.length - 1);
System.out.println("排序后的数组:");
for (int num : array) {
System.out.print(num + " ");
}
}
public static void quickSort(int[] array, int low, int high) {
if (low < high) {
// 将数组划分为两部分,返回枢轴元素的索引位置
int pivotIndex = partition(array, low, high);
// 对枢轴元素左边的子数组进行快速排序
quickSort(array, low, pivotIndex - 1);
// 对枢轴元素右边的子数组进行快速排序
quickSort(array, pivotIndex + 1, high);
}
}
public static int partition(int[] array, int low, int high) {
// 选取最右边元素作为枢轴元素
int pivot = array[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (array[j] < pivot) {
i++;
// 交换元素
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
// 将枢轴元素放到正确的位置上
int temp = array[i + 1];
array[i + 1] = array[high];
array[high] = temp;
return i + 1;
}
}
5、归并排序(Merge Sort)
public class MergeSort {
public static void main(String[] args) {
int[] array = {5, 3, 8, 6, 2, 7, 1, 4};
mergeSort(array);
System.out.println("Sorted array: " + Arrays.toString(array));
}
public static void mergeSort(int[] array) {
if (array.length <= 1) {
return;
}
int middle = array.length / 2;
int[] left = new int[middle];
int[] right = new int[array.length - middle];
// 将原始数组分割为左右两个子数组
for (int i = 0; i < middle; i++) {
left[i] = array[i];
}
for (int i = middle; i < array.length; i++) {
right[i - middle] = array[i];
}
// 递归地对左右两个子数组进行排序
mergeSort(left);
mergeSort(right);
// 合并两个有序子数组
merge(left, right, array);
}
public static void merge(int[] left, int[] right, int[] array) {
int leftIndex = 0;
int rightIndex = 0;
int arrayIndex = 0;
// 比较左右两个子数组的元素,依次放入原始数组中
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] <= right[rightIndex]) {
array[arrayIndex++] = left[leftIndex++];
} else {
array[arrayIndex++] = right[rightIndex++];
}
}
// 处理剩余的元素
while (leftIndex < left.length) {
array[arrayIndex++] = left[leftIndex++];
}
while (rightIndex < right.length) {
array[arrayIndex++] = right[rightIndex++];
}
}
}
6、堆排序(Heap Sort)
public class HeapSort {
public void sort(int arr[]) {
int n = arr.length;
// 构建堆(重新排序)
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
// 一个个交换元素
for (int i = n - 1; i >= 0; i--) {
// 移动当前根到尾部
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
// 通过调用 max heapify 方法来在剩余的元素上重新进行 heapify 操作
heapify(arr, i, 0);
}
}
void heapify(int arr[], int n, int i) {
int largest = i; // 初始化 largest 为根
int left = 2 * i + 1; // 左子节点
int right = 2 * i + 2; // 右子节点
// 如果左子节点大于根
if (left < n && arr[left] > arr[largest]) {
largest = left;
}
// 如果右子节点大于根
if (right < n && arr[right] > arr[largest]) {
largest = right;
}
// 如果最大的不是根
if (largest != i) {
int swap = arr[i];
arr[i] = arr[largest];
arr[largest] = swap;
// 递归地对受影响的子堆进行调整
heapify(arr, n, largest);
}
}
static void printArray(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String args[]) {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = arr.length;
HeapSort hs = new HeapSort();
hs.sort(arr);
System.out.println("Sorted array is");
printArray(arr);
}
}
查找算法
查找算法用于在大量数据中搜索目标元素。常见的查找算法包括:
1、线性查找(Linear Search)
public class LinearSearch {
public static int linearSearch(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
return -1; // 如果目标值不在数组中,则返回-1
}
public static void main(String[] args) {
int[] arr = {3, 5, 2, 8, 4};
int target = 8;
int index = linearSearch(arr, target);
if (index == -1) {
System.out.println("目标值不在数组中");
} else {
System.out.println("目标值在数组中的索引为:" + index);
}
}
}
2、二分查找(Binary Search)
public class BinarySearch {
public static int binarySearch(int[] arr, int target) {
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // 如果目标值不在数组中,则返回-1
}
public static void main(String[] args) {
int[] arr = {3, 5, 2, 8, 4};
int target = 8;
int index = binarySearch(arr, target);
if (index == -1) {
System.out.println("目标值不在数组中");
} else {
System.out.println("目标值在数组中的索引为:" + index);
}
}
}
3、哈希表(Hashing)
import java.util.LinkedList;
class HashTable<K, V> {
private class Entry<K, V> {
K key;
V value;
Entry<K, V> next;
Entry(K key, V value, Entry<K, V> next) {
this.key = key;
this.value = value;
this.next = next;
}
}
private LinkedList<Entry<K, V>>[] table;
private int capacity = 1000; // 哈希表容量
public HashTable() {
table = new LinkedList[capacity];
for(int i=0; i<capacity; i++) {
table[i] = new LinkedList<>();
}
}
private int hash(K key) {
return (Math.abs(key.hashCode())) % capacity;
}
public void put(K key, V value) {
int index = hash(key);
LinkedList<Entry<K, V>> entries = table[index];
for(Entry<K, V> entry : entries) {
if(entry.key.equals(key)) {
entry.value = value; // 替换已存在的键的值
return;
}
}
entries.add(new Entry<>(key, value, null)); // 添加新的键值对
}
public V get(K key) {
int index = hash(key);
LinkedList<Entry<K, V>> entries = table[index];
for(Entry<K, V> entry : entries) {
if(entry.key.equals(key)) {
return entry.value;
}
}
return null; // 如果键不存在,返回null
}
public void remove(K key) {
int index = hash(key);
LinkedList<Entry<K, V>> entries = table[index];
for(Entry<K, V> entry : entries) {
if(entry.key.equals(key)) {
entries.remove(entry); // 移除已存在的键值对
return;
}
}
}
}
图论算法
图论算法主要用于处理图结构数据,常见的图论算法包括:
1、广度优先搜索(Breadth-First Search)
import java.util.*;
public class BFS {
private int V; // 顶点数量
private LinkedList<Integer> adj[]; // 邻接表
BFS(int v) {
V = v;
adj = new LinkedList[v];
for (int i = 0; i < v; ++i)
adj[i] = new LinkedList();
}
void addEdge(int v, int w) {
adj[v].add(w);
}
void BFS(int s) {
boolean visited[] = new boolean[V];
LinkedList<Integer> queue = new LinkedList<Integer>();
visited[s] = true;
queue.add(s);
while (queue.size() != 0) {
s = queue.poll();
System.out.print(s + " ");
Iterator<Integer> i = adj[s].listIterator();
while (i.hasNext()) {
int n = i.next();
if (!visited[n]) {
visited[n] = true;
queue.add(n);
}
}
}
}
public static void main(String args[]) {
BFS g = new BFS(4);
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(1, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);
System.out.println("Following is Breadth First Traversal "+
"(starting from vertex 2)");
g.BFS(2);
}
}
2、深度优先搜索(Depth-First Search)
import java.util.*;
class Graph {
private int V; // 顶点数
private LinkedList<Integer> adj[]; //邻接表
// 构造函数
Graph(int v) {
V = v;
adj = new LinkedList[v];
for (int i=0; i<v; ++i)
adj[i] = new LinkedList();
}
// 函数将边添加到图形中
void addEdge(int v, int w) {
adj[v].add(w);
adj[w].add(v); // 图形是无向的
}
// DFS使用的函数
void DFSUtil(int v, boolean visited[]) {
// 将当前节点标记为已访问并打印
visited[v] = true;
System.out.print(v+" ");
// 对与该顶点相邻的所有顶点重复
Iterator<Integer> i = adj[v].listIterator();
while (i.hasNext()) {
int n = i.next();
if (!visited[n])
DFSUtil(n, visited);
}
}
// 进行DFS遍历的函数。它使用递归DFSUtil()
void DFS(int v) {
// 将所有顶点标记为未访问(在java中默认设置为false)
boolean visited[] = new boolean[V];
// 调用递归助手函数打印DFS遍历
DFSUtil(v, visited);
}
}
// 驱动程序代码
public class Main {
public static void main(String args[]) {
// 创建上图中给出的图形
int V = 5;
Graph g1 = new Graph(V);
g1.addEdge(0, 1);
g1.addEdge(0, 4);
g1.addEdge(1, 2);
g1.addEdge(1, 3);
g1.addEdge(1, 4);
g1.addEdge(2, 3);
g1.addEdge(3, 4);
System.out.println("Following is Depth First Traversal (starting from vertex 2)");
g1.DFS(2);
}
}
3、最短路径算法(Dijkstra's Algorithm)
import java.util.*;
public class DijkstraAlgorithm {
private static final int INF = Integer.MAX_VALUE;
public static void dijkstra(int[][] graph, int startVertex) {
int n = graph.length;
// 初始化距离数组
int[] distances = new int[n];
for (int i = 0; i < n; i++) {
distances[i] = INF;
}
distances[startVertex] = 0;
// 初始化访问状态数组
boolean[] visited = new boolean[n];
// 找到从起点到所有点的最短路径
for (int i = 0; i < n; i++) {
int minDistance = INF;
int minVertex = -1;
for (int j = 0; j < n; j++) {
if (!visited[j] && distances[j] < minDistance) {
minDistance = distances[j];
minVertex = j;
}
}
if (minVertex == -1) {
break;
}
visited[minVertex] = true;
for (int j = 0; j < n; j++) {
if (graph[minVertex][j] != 0 && !visited[j]) {
distances[j] = Math.min(distances[j], distances[minVertex] + graph[minVertex][j]);
}
}
}
// 输出从起点到所有点的最短路径长度
for (int i = 0; i < n; i++) {
if (distances[i] == INF) {
System.out.println("无法到达顶点 " + i);
} else {
System.out.println("从起点到顶点 " + i + " 的最短路径长度为 " + distances[i]);
}
}
}
public static void main(String[] args) {
int[][] graph = {
{0, 4, 0, 0, 0, 0, 0, 8, 0},
{4, 0, 8, 0, 0, 0, 0, 11, 0},
{0, 8, 0, 7, 0, 4, 0, 0, 2},
{0, 0, 7, 0, 9, 14, 0, 0, 0},
{0, 0, 0, 9, 0, 10, 0, 0, 0},
{0, 0, 4, 14, 10, 0, 2, 0, 0},
{0, 0, 0, 0, 0, 2, 0, 1, 6},
{8, 11, 0, 0, 0, 0, 1, 0, 7},
{0, 0, 2, 0, 0, 0, 6, 7, 0}
};
dijkstra(graph, 0);
}
}
4、最小生成树算法(Minimum Spanning Tree)
import java.util.Arrays;
class Graph {
private static final int INF = Integer.MAX_VALUE;
private int numVertices;
private int[][] adjacencyMatrix;
public Graph(int numVertices) {
this.numVertices = numVertices;
adjacencyMatrix = new int[numVertices][numVertices];
for (int[] row : adjacencyMatrix)
Arrays.fill(row, INF);
}
public void addEdge(int src, int dest, int weight) {
adjacencyMatrix[src][dest] = weight;
adjacencyMatrix[dest][src] = weight;
}
private int getMinVertex(boolean[] mstSet, int[] key) {
int minKey = INF;
int vertex = -1;
for (int i = 0; i < numVertices; i++) {
if (!mstSet[i] && key[i] < minKey) {
minKey = key[i];
vertex = i;
}
}
return vertex;
}
public void primMST() {
boolean[] mstSet = new boolean[numVertices];
int[] key = new int[numVertices];
int[] parent = new int[numVertices];
Arrays.fill(key, INF);
Arrays.fill(parent, -1);
key[0] = 0;
for (int i = 0; i < numVertices - 1; i++) {
int minVertex = getMinVertex(mstSet, key);
mstSet[minVertex] = true;
for (int j = 0; j < numVertices; j++) {
int edgeWeight = adjacencyMatrix[minVertex][j];
if (edgeWeight != INF && !mstSet[j] && edgeWeight < key[j]) {
parent[j] = minVertex;
key[j] = edgeWeight;
}
}
}
printMST(parent, key);
}
private void printMST(int[] parent, int[] key) {
System.out.println("Edge \tWeight");
for (int i = 1; i < numVertices; i++)
System.out.println(parent[i] + " - " + i + "\t" + key[i]);
}
}
public class Main {
public static void main(String[] args) {
Graph graph = new Graph(5);
graph.addEdge(0, 1, 2);
graph.addEdge(0, 3, 6);
graph.addEdge(1, 2, 3);
graph.addEdge(1, 3, 8);
graph.addEdge(1, 4, 5);
graph.addEdge(2, 4, 7);
graph.addEdge(3, 4, 9);
graph.primMST();
}
}
5、最大流算法(Max Flow)
import java.util.*;
public class MaxFlow {
private int V; // 顶点数
private int[][] capacity; // 容量矩阵
private int[] flow; // 流矩阵
private int[] parent; // 记录路径上的父节点
public MaxFlow(int[][] graph) {
V = graph.length;
capacity = new int[V][V];
flow = new int[V][V];
parent = new int[V];
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (i != j) {
capacity[i][j] = graph[i][j];
}
}
}
}
// 寻找增广路径并返回最大流
public int maxFlow(int s, int t) {
int maxFlow = 0;
boolean[] visited = new boolean[V];
while (bfs(s, t, visited)) {
int pathFlow = Integer.MAX_VALUE;
int sPathFlow = 0;
int sPath = parent[s];
while (sPath != -1) {
int v = sPath;
int u = parent[v];
pathFlow = Math.min(pathFlow, capacity[u][v] - flow[u][v]);
if (u == s) {
sPathFlow = pathFlow;
}
sPath = parent[sPath];
}
maxFlow += sPathFlow;
vPath(s, t, pathFlow);
}
return maxFlow;
}
// BFS寻找增广路径并标记路径上的顶点
private boolean bfs(int s, int t, boolean[] visited) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(s);
visited[s] = true;
parent[s] = -1;
while (!queue.isEmpty()) {
int u = queue.poll();
for (int v = 0; v < V; v++) {
if (!visited[v] && capacity[u][v] - flow[u][v] > 0) {
queue.offer(v);
visited[v] = true;
parent[v] = u;
}
}
}
return visited[t];
}
字符串算法
字符串算法用于处理文本和字符串数据,包括以下常见算法:
1、匹配算法(如KMP算法)
public class KMPAlgorithm {
public static void main(String[] args) {
String text = "ABABABABCABAAB";
String pattern = "ABABCABAA";
int[] next = getNextArray(pattern);
int index = kmpSearch(text, pattern, next);
if (index >= 0) {
System.out.println("Pattern found at index " + index);
} else {
System.out.println("Pattern not found");
}
}
public static int[] getNextArray(String pattern) {
int[] next = new int[pattern.length()];
next[0] = -1;
int i = 0, j = -1;
while (i < pattern.length() - 1) {
if (j == -1 || pattern.charAt(i) == pattern.charAt(j)) {
i++;
j++;
next[i] = j;
} else {
j = next[j];
}
}
return next;
}
public static int kmpSearch(String text, String pattern, int[] next) {
int i = 0, j = 0;
while (i < text.length() && j < pattern.length()) {
if (j == -1 || text.charAt(i) == pattern.charAt(j)) {
i++;
j++;
} else {
j = next[j];
}
}
if (j == pattern.length()) {
return i - j;
} else {
return -1;
}
}
}
2、排序算法(如基数排序)
public class RadixSort {
public static void sort(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
radixSort(arr, 0, arr.length - 1, maxBits(arr));
}
private static int maxBits(int[] arr) {
int max = Arrays.stream(arr).max().getAsInt();
return (int) (Math.log(max) / Math.log(2)) + 1;
}
private static void radixSort(int[] arr, int begin, int end, int digit) {
final int radix = 10;
int i = 0, j = 0;
int[] bucket = new int[end - begin + 1];
for (int d = 1; d <= digit; d++) {
int[] count = new int[radix];
for (i = begin; i <= end; i++) {
j = getDigit(arr[i], d);
count[j]++;
}
for (i = 1; i < radix; i++) {
count[i] += count[i - 1];
}
for (i = end; i >= begin; i--) {
j = getDigit(arr[i], d);
bucket[count[j] - 1] = arr[i];
count[j]--;
}
for (i = begin, j = 0; i <= end; i++, j++) {
arr[i] = bucket[j];
}
}
}
private static int getDigit(int x, int d) {
return ((x / ((int) Math.pow(10, d - 1))) % 10);
}
}