目录
概览
一、冒泡排序
1、算法描述
2、图示
3、代码
二、选择排序
1、算法描述
2、图示
3、代码
三、插入排序
1、算法描述
2、图示
编辑 3、代码
四、希尔排序
1、算法描述
2、图示
3、代码
五、并归排序
1、算法描述
2、图示
编辑编辑3、代码
六、快速排序
1、算法描述
2、图示
编辑编辑 3、代码
七、堆排序
1、算法描述
2、图示
3、代码
八、计数排序
1、算法描述
2、图示
3、代码
九、桶排序
1、算法描述
2、图示
3、代码
十、基数排序
1、算法描述
2、图示
3、代码
十大排序算法可以分成两类:
算法的时间复杂度:
相关概念:
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。
!!以下算法均按照升序排序!!
从头开始,一次比较相邻的两个元素,如果前一个元素比后一个元素小,则往后移动一个元素继续比较;如果前一个元素比后一个元素大,则两个元素交换位置,再往后移一个元素继续比较。
每一趟比较下来,最后一个元素肯定是当前趟最大的,进行下一趟比较时,该元素就不再参与比较了。
function bubbleSort(arr) {
let len = arr.length;
// 一共比较多少趟
for (let i = 0; i < len - 1; i++) {
// 每趟进行比较,j=要进行排序的元素个数,每一趟排下来最后1个元素都不进行下一趟的排序
for (let j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr;
}
let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
console.log(bubbleSort(arr)); // [3, 4, 5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
每趟比较中找到最小的元素,将最小的元素与首元素进行位置交换,首元素就不再进行下一趟排序,重复操作直到完成排序
function selectSort(arr) {
let len = arr.length;
for (let i = 0; i < len - 1; i++) {
let minIndex = i; // 记录最小元素的索引
for (let j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j; // 如果有遇到比首元素小的,就记录该索引,这样就能找到当前趟最小元素的索引
}
}
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]; // 交换首元素和最小元素的位置
}
return arr;
}
let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
console.log(selectSort(arr)); // [3, 4, 5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
function insertSort(arr) {
let len = arr.length;
for (let i = 1; i < len; i++) {
let now = arr[i]; // 当前趟的元素
let lastIndex = i - 1; // 已经排好序的序列里的最后一个元素
// 从后向前遍历已经排好序的序列
// 如果当前趟的元素now比已经排好序的序列的元素小
while (lastIndex >= 0 && arr[lastIndex] > now) {
arr[lastIndex + 1] = arr[lastIndex]; // 将比now大的元素向后移一个位置
lastIndex--;
}
arr[lastIndex + 1] = now; // 将当前趟的元素now插入到已经排好序的序列里
}
return arr;
}
let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
console.log(insertSort(arr)); // [3, 4, 5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
插入排序的改进版。与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
function shellSort(arr) {
let len = arr.length;
// 第一次分组是k=arr.length/2,之后的每次分组都是k/2
for (let k = Math.floor(len / 2); k > 0; k = Math.floor(k / 2)) {
// 遍历每个分组的元素,i在分组里表示的是每个组内最后一个元素
// 在原数组arr里表示的是分组后的第一个元素,然后后面的元素依次与前面的元素进行比较
for (let i = k; i < len; i++) { // i控制当前进行排序的是哪一个小组
let j = i; // j控制的是当前小组的最后一个元素
// 各小组内进行比较时,按升序排列
while (j - k >= 0 && arr[j] < arr[j - k]) {
[arr[j], arr[j - k]] = [arr[j - k], arr[j]];
j = j - k; // 让j变成当前小组的上一个元素
}
}
}
return arr;
}
let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
console.log(shellSort(arr)); // [3, 4, 5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
分治法
把长度为n的arr分成两个长度为n/2的子序列,一直划分到最小个数之后,两两比较,合并成长度为2的小序列,然后再小序列间比较,一直重复合并成最终的arr
function mergeSort(arr) {
let len = arr.length;
if (len < 2) {
return arr;
}
let mid = Math.floor(len / 2);
let left = arr.slice(0, mid);
let right = arr.slice(mid);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right) {
let result = [];
while (left.length > 0 && right.length > 0) {
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 = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
console.log(mergeSort(arr)); // [3, 4, 5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
分治法
function quickSort(arr, left, right) {
let len = arr.length,
partitionIndex,
left = typeofleft != "number" ? 0 : left,
right = typeofright != "number" ? len - 1 : right;
if (left < right) {
partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, right);
}
return arr;
}
function partition(arr, left, right) {
// 分区操作
let pivot = left, // 设定基准值(pivot)
index = pivot + 1;
for (let i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
return index - 1;
}
function swap(arr, i, j) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
console.log(quickSort(arr)); // [3, 4, 5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
var len; // 因为声明的多个函数都需要数据长度,所以把len设置成为全局变量
function buildMaxHeap(arr) {
// 建立大顶堆
len = arr.length;
for (var i = Math.floor(len / 2); i >= 0; i--) {
heapify(arr, i);
}
}
function heapify(arr, i) {
// 堆调整
var left = 2 * i + 1,
right = 2 * i + 2,
largest = i;
if (left < len && arr[left] > arr[largest]) {
largest = left;
}
if (right < len && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {
swap(arr, i, largest);
heapify(arr, largest);
}
}
function swap(arr, i, j) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function heapSort(arr) {
buildMaxHeap(arr);
for (var i = arr.length - 1; i > 0; i--) {
swap(arr, 0, i);
len--;
heapify(arr, 0);
}
return arr;
}
let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];
console.log(heapSort(arr)); // [3, 4, 5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
function countingSort(arr, maxValue) {
let bucket = newArray(maxValue + 1),
sortedIndex = 0;
(arrLen = arr.length), (bucketLen = maxValue + 1);
for (let i = 0; i < arrLen; i++) {
if (!bucket[arr[i]]) {
bucket[arr[i]] = 0;
}
bucket[arr[i]]++;
}
for (let j = 0; j < bucketLen; j++) {
while (bucket[j] > 0) {
arr[sortedIndex++] = j;
bucket[j]--;
}
}
return arr;
}
function bucketSort(arr, bucketSize) {
if (arr.length === 0) {
return arr;
}
let minValue = arr[0];
let maxValue = arr[0];
for (let i = 1; i < arr.length; i++) {
if (arr[i] < minValue) {
minValue = arr[i]; // 输入数据的最小值
} else if (arr[i] > maxValue) {
maxValue = arr[i]; // 输入数据的最大值
}
}
// 桶的初始化
let DEFAULT_BUCKET_SIZE = 5; // 设置桶的默认数量为5
bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
let bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;
let buckets = newArray(bucketCount);
for (let i = 0; i < buckets.length; i++) {
buckets[i] = [];
}
// 利用映射函数将数据分配到各个桶中
for (let i = 0; i < arr.length; i++) {
buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
}
arr.length = 0;
for (let i = 0; i < buckets.length; i++) {
insertionSort(buckets[i]); // 对每个桶进行排序,这里使用了插入排序
for (let j = 0; j < buckets[i].length; j++) {
arr.push(buckets[i][j]);
}
}
return arr;
}
let counter = [];
function radixSort(arr, maxDigit) {
let mod = 10;
let dev = 1;
for (let i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
for (let j = 0; j < arr.length; j++) {
let bucket = parseInt((arr[j] % mod) / dev);
if (counter[bucket] == null) {
counter[bucket] = [];
}
counter[bucket].push(arr[j]);
}
let pos = 0;
for (let j = 0; j < counter.length; j++) {
let value = null;
if (counter[j] != null) {
while ((value = counter[j].shift()) != null) {
arr[pos++] = value;
}
}
}
}
return arr;
}