(() => {
// 冒泡排序
let arr = [];
/**
* 从数组的第0个索引开始依次从左到右比较数组中的最小值,如果右边的值比左边小,那么交换值,这样右边的值一直都是最大的值
* 从而将最大的值冒泡到数组的最后一个索引的位置
* 然后从第1...n个索引循环 使用依次从左到右比较数组中的最小值,如果右边的值比左边小,那么交换值 冒泡到第n-1...0个索引
* @param {*} size
*/
function bubble(size) {
initArr(size);
let isChange = false;
for (let index = 0; index < arr.length; index++) {
isChange = false;
for (let k = 1; k < arr.length - index; k++) {
if (arr[k - 1] > arr[k]) {
[arr[k - 1], arr[k]] = [arr[k], arr[k - 1]];
isChange = true;
}
}
if (!isChange) { // 优化
console.log("提前结束冒泡排序: " + index);
break;
}
}
console.log("冒泡排序后: ", arr);
}
/**
* 从第0个索引开始找到数组中最小的值,然后交换最小值到0索引 将0索引的值赋值到最小值索引
* 然后依次 从第1....n个索引开始找出数组中最小的值 在次交换
* 直到第n个索引将数组全部完成此操作就将数组排序了
* @param {*} size
*/
function selectSort(size) { // 相对于冒泡排序减少了频繁的交换数组位置的操作平均下来时间上优于冒泡排序
initArr(size);
let minIndex = 0;
for (let index = 0; index < arr.length; index++) {
minIndex = index;
for (let j = index + 1; j < arr.length; j++) { // 找到未排序区间中一个最小的值的index
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
if (minIndex != index) {
let temp = arr[index];
arr[index] = arr[minIndex];
arr[minIndex] = temp;
// 在java语言中根据视频结果得知 插入排序的平均执行时间是大于选择排序的,但是在js中 结果却是相反的,也不是下面这句话造成的
// [arr[minIndex], arr[index]] = [arr[index], arr[minIndex]]; // 交换最小值到下一个排队点
}
}
}
/**
* 插入排序 将数组分成两部分看待 一部分是 0-(n-1)的有序数组 一部分是n-length-1的无序数组
* 保存第n个索引的数值,和有序数组中 (n-1) ~ 0依次比较,如果有序数组中的数值大于第n个索引的数值
* 那么将有序数组中当前比较索引的数值赋值给 +1 的索引,否则 当前索引就是目标位置,将保存的插入数值进行复制即可
* @param {*} size
*/
function insterSort(size) {
initArr(size);
let crtIdx = 0;
let crtVal = 0;
for (let index = 1; index < arr.length; index++) {
crtIdx = index - 1;
crtVal = arr[index];
while (crtIdx >= 0 && crtVal < arr[crtIdx]) { // 如果有序数组中的数值大于了插入数值那么就将有序数组中的数值往后排
arr[crtIdx + 1] = arr[crtIdx];
crtIdx--;
}
arr[crtIdx + 1] = crtVal;
}
}
function shellInsertSort(size) {
initArr(size);
// let excuteCount = 0;
let crtIdx = crtVal = 0;
for (let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) {
for (let i = gap; i < arr.length; i++) {
crtIdx = i;
crtVal = arr[i];
// if(arr[i - gap] > arr[i]){ // 比较当前的值和 下一个值是否存在逆序
while(crtIdx-gap >= 0 && crtVal < arr[crtIdx-gap]){ // 使用插入排序的方式
arr[crtIdx] = arr[crtIdx-gap]; // 仅仅是将数字赋值到下一个索引
crtIdx -= gap;
}
arr[crtIdx] = crtVal; // 最后一次切换顺序
// }
}
// console.log(`希尔排序第${++excuteCount}轮`, arr);
}
}
function shellSort(size) {
initArr(size);
// let excuteCount = 0;
for (let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) {
for (let i = gap; i < arr.length; i++) {
for (let j = i; j >= gap; j -= gap) {
if (arr[j] < arr[j - gap]) { // 只要有顺序问题就会交换,如果是最小的值那么就会全部进行交换
[arr[j], arr[j - gap]] = [arr[j - gap], arr[j]];
}
}
}
// console.log(`希尔排序第${++excuteCount}轮`, arr);
}
/*
for (let i = gap; i < arr.length; i++) {
changeIndex = i;
changeVal = arr[i];
for (let j = i; j >= gap; j -= gap) {
if (changeVal < arr[j - gap]) {
arr[j] = arr[j - gap];
changeIndex = j - gap;
}
}
arr[changeIndex] = changeVal;
}
*/
// 记录算法逻辑过程
/*let test = [8, 9, 1, 7, 2, 3, 5, 4, 6, 0, 3];
// 第一轮 根据数组长度将其分组 Math.floor(test.length / 2); 也就是 5组
// 再将每组进行排序
for (let i = 5; i < test.length; i++) {
for (let j = i; j >= 5; j -= 5) {
if (test[j] < test[j - 5]) {
[test[j], test[j - 5]] = [test[j - 5], test[j]]; // 交换
}
}
}
console.log("希尔第一轮: ", test);
// 第二轮 根据数组长度将其分组 Math.floor(test.length / 2 / 2); 也就是 2组
// 再将每组进行排序
for (let i = 2; i < test.length; i++) {
for (let j = i; j >= 2; j -= 2) { // 将分组内的数组进行排序,这样这两组数组是有序的
if (test[j] < test[j - 2]) {
[test[j], test[j - 2]] = [test[j - 2], test[j]]; // 交换
}
}
}
console.log("希尔第二轮: ", test);
// 第三轮 根据数组长度将其分组 Math.floor(test.length / 2 / 2 / 2); 也就是 1组
// 再将每组进行排序
for (let i = 1; i < test.length; i++) {
for (let j = i; j >= 1; j -= 1) { // 从索引1开始 到 length-1 和数组的起始位置进行比较并排序
if (test[j] < test[j - 1]) {
[test[j], test[j - 1]] = [test[j - 1], test[j]]; // 交换
}
}
}
console.log("希尔第三轮: ", test);*/
}
function initArr(size) {
arr = new Array(size);
for (let index = 0; index < size; index++) {
arr[index] = Math.floor(Math.random() * size)
}
console.log("随机初始化数组", arr);
}
let size = 80000;
console.time("冒泡时间:");
bubble(size);
console.timeEnd("冒泡时间:");
console.time("选择时间:");
selectSort(size);
console.log("排序结果", arr);
console.timeEnd("选择时间:");
console.time("插入时间:");
insterSort(size);
console.log("排序结果", arr);
console.timeEnd("插入时间:");
console.time("希尔时间:");
shellSort(size);
console.log("排序结果", arr);
console.timeEnd("希尔时间:");
console.time("希尔2时间:");
shellInsertSort(size);
console.log("排序结果", arr);
console.timeEnd("希尔2时间:");
})();