一. 递归算法
递归算法是一种解决问题的有效方法,尤其是在处理嵌套结构的数据时。例如,在处理DOM树、解析JSON数据等方面,递归算法都有广泛的应用
// 计算一个数的阶乘
function fn(n){
if(n === 1) {
return 1
}
return n*fn(n-1)
}
// 说明 递归终止条件, 当n为1时,只返回 1,后续不再调用自身
二. 排序算法
排序算法在计算机科学中是非常基础和重要的概念。它们被用于将数据元素按照某种顺序(通常是升序或降序)进行排列。
1. 冒泡排序(Bubble Sort)
冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
function bubbleSort(arr) {
let len = arr.length;
for (let i = 0; i < len - 1; i++) {
for (let j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) { // 相邻元素两两对比
let temp = arr[j + 1]; // 元素交换
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
let arr = [34, 8, 64, 51, 32, 21];
console.log(bubbleSort(arr)); // [8, 21, 32, 34, 51, 64]
2. 选择排序(Selection Sort)
选择排序是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
function selectionSort(arr) {
let len = arr.length;
let minIndex, temp;
for (let i = 0; i < len - 1; i++) {
minIndex = i;
for (let j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
let arr = [34, 8, 64, 51, 32, 21];
console.log(selectionSort(arr)); // [8, 21, 32, 34, 51, 64]
3. 插入排序(Insertion Sort)
插入排序的工作方式是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
function insertionSort(arr) {
let len = arr.length;
let preIndex, current;
for (let i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex];
preIndex--;
}
arr[preIndex + 1] = current;
}
return arr;
}
let arr = [34, 8, 64, 51, 32, 21];
console.log(insertionSort(arr)); // [8, 21, 32, 34, 51, 64]
4. 快速排序(Quick Sort)
快速排序是一种分而治之的排序算法。它选择一个元素作为“基准”(pivot),然后将数组分成两个子数组:一个包含比基准小的元素,另一个包含比基准大的元素。然后对这两个子数组进行快速排序。
function quickSort(arr) {
if (arr.length <= 1) return arr;
let pivotIndex = Math.floor(arr.length / 2);
let pivot = arr.splice(pivotIndex, 1)[0];
let left = [];
let right = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
return quickSort(left).concat([pivot], quickSort(right));
}
let arr = [34, 8, 64, 51, 32, 21];
console.log(quickSort(arr)); // [8, 21, 32, 34, 51, 64]
5. 归并排序(Merge Sort)
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。
function mergeSort(arr) {
if (arr.length < 2) {
return arr;
}
let middle = Math.floor(arr.length / 2);
let left = arr.slice(0, middle);
let right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
let result = [];
while (left.length && right.length) {
if (left[0] <= right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
while (left.length) {
result.push(left.shift());
}
while (right.length) {
result.push(right.shift());
}
return result;
}
let arr = [34, 8, 64, 51, 32, 21];
console.log(mergeSort(arr)); // [8, 21, 32, 34, 51, 64]
冒泡排序和选择排序在数据量小的时候简单且有效,但在大数据量下效率较低。插入排序对于部分有序的数据集效率较高。快速排序和归并排序在处理大数据集时表现出色,但快速排序在最坏情况下的时间复杂度为O(n^2),而归并排序的时间复杂度始终为O(n log n)。
在实际的前端开发中,排序算法可能用于优化渲染列表、处理用户输入数据、进行数据库查询结果的排序等场景。选择哪种排序算法取决于具体的需求和场景。
三.查找算法
查找算法是计算机科学中的一个基础概念,用于在数据结构(如数组、列表、树、图等)中快速找到特定的元素。不同的查找算法在不同的数据结构和场景下有不同的效率。
1. 线性查找(Linear Search)
线性查找是最简单直观的查找算法。它按顺序逐个比较数据集中的每一个元素,直到找到目标元素或者搜索完整个数据集。
function linearSearch(arr, target) {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === target) {
return i; // 返回目标元素的索引
}
}
return -1; // 如果没有找到目标元素,返回-1
}
let arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
let target = 5;
console.log(linearSearch(arr, target)); // 输出目标元素的索引,例如:4 或 7 或 9
2. 二分查找(Binary Search)
二分查找是一种高效的查找算法,它要求数据集必须是有序的。算法每次比较中间元素,如果中间元素正好是目标值,则搜索结束;如果目标值小于中间元素,则在左半部分继续搜索;反之则在右半部分继续搜索。
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid; // 返回目标元素的索引
}
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // 如果没有找到目标元素,返回-1
}
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let target = 5;
console.log(binarySearch(arr, target)); // 输出目标元素的索引,例如:4
3. 哈希查找(Hash Search)
哈希查找利用哈希表(一种特殊的数据结构)来实现快速查找。哈希表通过哈希函数将键映射到存储位置,从而可以直接访问对应的值。
在JavaScript中,对象本质上是一个哈希表,键是唯一的,并且可以通过键直接访问对应的值。
let hashTable = {
"apple": "fruit",
"banana": "fruit",
"carrot": "vegetable"
};
function hashSearch(hashTable, key) {
if (hashTable.hasOwnProperty(key)) {
return hashTable[key]; // 返回与键对应的值
}
return null; // 如果没有找到键,返回null
}
console.log(hashSearch(hashTable, "apple")); // 输出:"fruit"
4. 树查找
树查找算法通常用于在树形数据结构中查找元素,如二叉搜索树(Binary Search Tree)。
在二叉搜索树中,每个节点包含一个值,并且对于树中的每个节点,其左子树中的所有值都小于或等于该节点的值,而右子树中的所有值都大于或等于该节点的值。这使得在树中查找元素变得非常高效。
下面是一个简单的二叉搜索树的查找实现:
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
function searchBST(root, target) {
if (root === null) {
return false; // 树为空,未找到目标
}
if (root.value === target) {
return true; // 找到目标
}
if (root.value < target) {
return searchBST(root.right, target); // 在右子树中继续查找
}
return searchBST(root.left, target); // 在左子树中继续查找
}
// 构建一个简单的二叉搜索树
let root = new Node(5);
root.left = new Node(3);
root.right = new Node(7);
root.left.left = new Node
(2);
root.left.right = new Node(4);
root.right.left = new Node(6);
root.right.right = new Node(8);
// 在二叉搜索树中查找目标值
let target = 6;
console.log(searchBST(root, target)); // 输出:true,表示找到了目标值
target = 9;
console.log(searchBST(root, target)); // 输出:false,表示未找到目标值
树查找还可以应用于其他类型的树,如AVL树、红黑树等,它们都是为了保持树的平衡而设计的,以确保查找、插入和删除操作的时间复杂度尽可能低。
5. 散列表查找(Hash Table Search)
散列表查找是一种基于哈希表实现的查找算法。它通过哈希函数将键映射到数组中的某个位置,从而可以快速访问对应的值。
在JavaScript中,你可以使用对象作为哈希表,键是唯一的,并且可以通过键直接访问对应的值。
// 创建一个哈希表
let hashTable = {
"key1": "value1",
"key2": "value2",
"key3": "value3"
};
// 散列表查找函数
function hashTableSearch(hashTable, key) {
if (hashTable.hasOwnProperty(key)) {
return hashTable[key]; // 返回与键对应的值
}
return null; // 如果没有找到键,返回null
}
// 查找哈希表中的元素
console.log(hashTableSearch(hashTable, "key1")); // 输出:"value1"
console.log(hashTableSearch(hashTable, "key4")); // 输出:null
6. 字典树查找(Trie Search)
字典树(Trie)是一种特殊的树形数据结构,用于高效地存储和查找字符串数据集中的键。
class TrieNode {
constructor() {
this.children = {};
this.isEndOfWord = false;
}
}
class Trie {
constructor() {
this.root = new TrieNode();
}
insert(word) {
let currentNode = this.root;
for (let char of word) {
if (!currentNode.children[char]) {
currentNode.children[char] = new TrieNode();
}
currentNode = currentNode.children[char];
}
currentNode.isEndOfWord = true;
}
search(word) {
let currentNode = this.root;
for (let char of word) {
if (!currentNode.children[char]) {
return false;
}
currentNode = currentNode.children[char];
}
return currentNode.isEndOfWord;
}
}
// 使用字典树查找
let trie = new Trie();
trie.insert("hello");
trie.insert("world");
console.log(trie.search("hello")); // 输出:true
console.log(trie.search("world")); // 输出:true
console.log(trie.search("hi")); // 输出:false
以上介绍了几种常见的查找算法,每种算法都有其适用的场景和优缺点。在实际应用中,需要根据具体的需求和数据结构的特点来选择合适的查找算法。