1、冒泡排序的思路
一个有
8位元素的数组,让它的第一位与后面每一位进行比较,前面一位小于后面的时候,位置不变,前面的大于后面的交换位置,就这样一共要比七趟(最后一趟不要比,就剩一位,就是最小的);
实现原理如下图:
2、按性能等级冒泡排序分3个等级
1、冒泡排序(初级):
let arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
let tang = 0;
let ci = 0;
for (let i = 0; i < arr.length - 1; i++) { // 外层for循环,循环的是比较的趟数,因为只要比较8趟 所以i判断的条件为length-1
tang++;
for (let j = 0; j < arr.length - 1; j++) { // 内层for循环,循环的是比较的次数,每趟比较8次
ci++;
if (arr[j] > arr[j + 1]) { // 判断比较的两个数,如果前面的大于后面的一位,交换位置
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log("趟数:" + tang); // 8趟
console.log("次数:" + ci); // 64次
console.log(arr);
}
- 外层
for循环,循环的是比较的趟数,因为只要比较8趟(数组长度为9) 所以i判断的条件为length-1; - 内层
for循环,循环的是比较的次数,每趟比较8次,其实这里次数多比较了,因为第一趟已经找到一个最大值了,第二趟就不需要比8次了 应该比7次,这里先不管,下面会进行优化; - 判断比较的两个数,如果前面的大于后面的一位,交换位置。
测试代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<span id="demo"></span><br/>
<button id="stb">从小到大</button>
<button id="bts">从大到小</button>
<span id="show"></span>
<script>
let demo = document.getElementById("demo");
let show = document.getElementById("show");
let bts = document.getElementById("bts");
let stb = document.getElementById("stb");
let arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
demo.innerHTML = arr;
bts.onclick = function() {
bubbleSort(function(a, b) {
return b - a;
});
}
stb.onclick = function() {
bubbleSort(function(a, b) {
return a - b;
});
}
function bubbleSort(fn) {
let arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
let strArr = [];
show.innerHTML = "";
strArr.push("<br/>");
let inner = 0;
let outer = 0;
for (let i = 0; i < arr.length - 1; i++) {
strArr.push("第" + (i + 1) + "趟");
for (let j = 0; j < arr.length - 1; j++) {
if (fn(arr[j], arr[j + 1]) > 0) {
let tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
inner++;
}
strArr.push(arr.toString());
strArr.push("共" + j + "次" + "<br/>");
outer++;
}
strArr.push("外循环" + outer + "次");
strArr.push("内循环" + inner + "次");
show.innerHTML = strArr.join(" ");
}
</script>
</body>
</html>
每趟都比较8次?明显是多余了,下面进行优化
2、冒泡排序(中级):
let arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
let tang = 0;
let ci = 0;
for (let i = 0; i < arr.length - 1; i++) {
tang++;
for (let j = 0; j < arr.length - 1 - i; j++) { // 第二趟只比了7次 依次递减
ci++;
if (arr[j] > arr[j + 1]) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log("趟数:" + tang); // 8趟
console.log("次数:" + ci); // 36次
console.log(arr);
i 是从下标0开始的,第一趟的时候i=0,比了8次,第二趟i=1,只需要比7次,第三趟i=2,只需要比6次...依次类推,所以 比的次数应该就是arr.length - 1 -i;
测试代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<span id="demo"></span><br/>
<button id="stb">从小到大</button>
<button id="bts">从大到小</button>
<span id="show"></span>
<script>
let demo = document.getElementById("demo");
let show = document.getElementById("show");
let bts = document.getElementById("bts");
let stb = document.getElementById("stb");
let arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
demo.innerHTML = arr;
bts.onclick = function() {
bubbleSort(function(a, b) {
return b - a;
});
}
stb.onclick = function() {
bubbleSort(function(a, b) {
return a - b;
});
}
function bubbleSort(fn) {
let arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
let strArr = [];
show.innerHTML = "";
strArr.push("<br/>");
let inner = 0;
let outer = 0;
for (let i = 0; i < arr.length - 1; i++) {
strArr.push("第" + (i + 1) + "趟");
for (let j = 0; j < arr.length - 1 - i; j++) {
if (fn(arr[j], arr[j + 1]) > 0) {
let tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
inner++;
}
strArr.push(arr.toString());
strArr.push("共" + j + "次" + "<br/>");
outer++;
}
strArr.push("外循环" + outer + "次");
strArr.push("内循环" + inner + "次");
show.innerHTML = strArr.join(" ");
}
</script>
</body>
</html>
还有什么可以优化的吗? 假如8个数在第3趟的时候就排好了,还需要继续排吗?
3、冒泡排序(高级):
假设成立法(3步):
- 假设成立
- 想办法推翻假设
- 如果推翻不了,说明假设成立
let arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
let tang = 0;
let ci = 0;
for (let i = 0; i < arr.length - 1; i++) {
let flag = true; // 假设每一次进来都排好了
tang++;
for (let j = 0; j < arr.length - 1 - i; j++) {
ci++;
if (arr[j] > arr[j + 1]) {
flag = false; // 如果两位比较还满足前面的比后面的大的时候,说明假设不成立
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
if (flag == true) { // 最后判断一下,如果假设推翻不了,就停止运行。
break;
}
}
console.log("趟数:" + tang); // 4 趟
console.log("次数:" + ci); // 26 次
console.log(arr);
当顺序已经排好后,就不用再去执行趟数了;
测试代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<span id="demo"></span><br/>
<button id="stb">从小到大</button>
<button id="bts">从大到小</button>
<span id="show"></span>
<script>
let demo = document.getElementById("demo");
let show = document.getElementById("show");
let bts = document.getElementById("bts");
let stb = document.getElementById("stb");
let arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
demo.innerHTML = arr;
bts.onclick = function() {
bubbleSort(function(a, b) {
return b - a;
});
}
stb.onclick = function() {
bubbleSort(function(a, b) {
return a - b;
});
}
function bubbleSort(fn) {
let arr = [3, 1, 2, 5, 4, 8, 9, 7, 6];
let strArr = [];
show.innerHTML = "";
strArr.push("<br/>");
let inner = 0;
let outer = 0;
for (let i = 0; i < arr.length - 1; i++) {
let sorted = true;
strArr.push("第" + (i + 1) + "趟");
for (let j = 0; j < arr.length - 1 - i; j++) {
if (fn(arr[j], arr[j + 1]) > 0) {
let tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
sorted = false;
}
inner++;
}
strArr.push(arr.toString());
strArr.push("共" + j + "次" + "<br/>");
outer++;
if (sorted) {
break;
}
}
strArr.push("外循环" + outer + "次");
strArr.push("内循环" + inner + "次");
show.innerHTML = strArr.join(" ");
}
</script>
</body>
</html>
第三趟已经排好了,为什么还要排第四趟呢? 原因很简单,因为第三趟的时候js是不知道你已经排好的,只有第四趟的时候,js再进行换位比较的时候,发现位置都不需要换了,说明排好了。