-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 54 题:冒泡排序如何实现,时间复杂度是多少, 还可以如何改进? #94
Comments
刚好这有一篇文章解答了今天面试题https://www.jianshu.com/p/5d44186b5263 |
function bubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
const temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log(arr);
}
// 改进冒泡排序
function bubbleSort1(arr) {
let i = arr.length - 1;
while (i > 0) {
let pos = 0;
for (let j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
pos = j;
const temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
i = pos;
}
console.log(arr);
} |
补充一个 function bubbleSort2(arr) {
let low = 0;
let high = arr.length - 1;
let temp, j;
while (low < high) {
// 正排找最大
for (j = low; j < high; ++j) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
--high;
// 反排找最小
for (j = high; j > low; --j) {
if (arr[j] < arr[j - 1]) {
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
++low;
}
console.log(arr);
} |
时间复杂度: O(n2)
let arr = [ 2, 3, 4, 44, 9, 4, 3, 2, 5, 1, 65, 2, 3, 6 ]
for(let i = 0; i < arr.length; i++ ) {
for(let j = i + 1; j < arr.length; j++) {
if(arr[i] > arr[j]) {
let beforeVar = arr[i]
arr[i] = arr[j]
arr[j] = beforeVar
}
}
} |
冒泡排序
时间复杂度(大O计数法):O(n^2)
|
我喜欢 |
|
bubble |
@guokangf 这个改良算法能解释一下吗? |
// 冒泡排序
const bubbleSort = (array) => {
const newArray = [...array]
const len = newArray.length
if (len <= 1) return
let isChange = false
for(let i = 0; i < len; i++) {
for (let j = i; j < len - i - 1; j++) {
if (newArray[j + 1] < newArray[j]) {
let temp = newArray[j + 1]
newArray[j + 1] = newArray[j]
newArray[j] = temp
isChange = true
}
}
if (!isChange) break
}
return newArray
} 时间复杂度 O(n^2) |
function random(n,x,y){
let arr = [];
for(let i = 0; i < n; i++){
let num = (x + Math.random() * (y - x)) | 0;
arr.push(num);
}
return arr;
};
function sort(arr){
let leng = arr.length;
for(let i = 0; i < leng; i++){
for(let j = 0; j < leng - i - 1; j++){
if(arr[j] > arr[j + 1]){
let tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
return arr;
}
console.log(sort(random(5,5,50))); 练个手 |
arr = [5,4,22,33,11,66] |
每次最大值放到最右后,会将本轮最后一个操作的位置作为下一轮的终点,可以减少不必要的一些冒泡 |
|
var bubbleSort = function(arr) {
var temp = null;
for (var i=arr.length-1;i>=0;i--){
var flag = true; // 循环开始时设置一个flag为true,若在一个循环中没有发生交换,则数组已经有序,可以直接退出
for (var j=0;j<i;j++) {
if(arr[j]>arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = false;
}
}
if(flag) break;
}
return arr;
} |
长知识了~ |
根据上述代码,我们每一轮冒泡需要的结果就是把最大的数通过冒泡放到最后,然后缩小下一轮需要冒泡的数组的范围(未优化的方案中数组范围只缩小了一位),但是实际上我们每一轮冒泡后可能会出现后面的几个数都有序的情况,这个时候我们完全可以再缩小一点下一次需要冒泡的数组的范围(不然下一轮冒泡到最后发现最大的数本来就在最后,此次冒泡就是多余的)。那怎么确定这个i值呢? 举个栗子: |
@wwwxy80s 我这边的冒泡排序的改良思路是,如果某一次遍历,没有进入过if条件,则表示已经是排好的顺序了,跳出循环 |
function bubbleSort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - 1 - i; j++) { // 此处还需要减去i 每一次排序都会排序好i 个数据
let temp = '';
if (arr[j] > arr[j + 1]) {
temp = arr[j]
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
bubbleSort([1,4,3,5,2,10,8,9])
function bubbleSort2(arr) {
for (let i = 0; i < arr.length - 1; i++) {
let finish = true;
let pos = 0;
let len = arr.length - 1 - i;
for(let j = 0; j < len; j++) {
let temp = '';
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
finish = false; // 是否还有交换 ,没有互换则代表排序排好了
pos = j // 最后一次交换的位置,之后的数据不需要再遍历
}
}
len = pos;
if (finish) {
break;
}
}
return arr;
}
bubbleSort2([1,4,3,5,2,10,8,9]) |
时间复杂度: O(n^2) 一般的冒泡: function bubbleSort1(arr) {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
} 这个存在的问题是,每次循环一次,后面就会多一段有序的数组,然而每次还是遍历了,是多余了 优化一下这个问题 function bubbleSort2(arr) {
// i是j需要遍历的次数,并不用i来遍历内容。
// 这样,每次会把上一次排过的数组滤过,只排列前面还没有排列的部分
// 每一次j就可以少遍历一次
for (let i = arr.length-1; i >= 0; i--) {
for (let j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
} 对于这个方案,还可以改进 function bubbleSort3(arr) {
var swapedFlag;
for (var i = arr.length - 1; i >= 0; i--) {
swapedFlag = false;
for (var j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
swapedFlag = true;
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
// 如果j遍历,从头到尾都没有把swapedFlag置为true,就证明剩下的一段数组,本来就是按顺序的,就不用再遍历了
if (!swapedFlag) {
break;
}
}
} |
普通:冒泡排序 |
标准实现中的 j < arr.length - i - 1; 循环条件不已经达到这个目的了吗?? |
这个改进版 是不是 每次取最后一次调换位置的下标 作为 下一次循环的长度????? |
不一样的 改良版的可以跳跃的 j < arr.length - i - 1 标准的是 每次都是一次递减的,不管是不是存在部分冒泡好的 |
|
另一种写法: function bubbleSortV2(arr) {
if (!arr || !arr.length) {
return [];
}
for (let r = arr.length-1; r > 0; ) {
let tempIndex = 0;
for (let l = 0; l < r; l++) {
if (arr[l] > arr[l + 1]) {
// 缩小需要冒泡的范围
tempIndex = l;
[arr[l], arr[l + 1]] = [arr[l + 1], arr[l]];
}
}
// 更新冒泡范围
r = tempIndex;
}
} |
冒泡排序概念:依次比较相邻的两个元素,如果顺序倒置则交换相邻元素。🤣🤣🤣 |
|
这篇文章里面的 break 应该换成 continue |
const getRandomArray = (max = 100, len = 10) => {
return Array.from(new Array(len)).map(() => Math.floor(Math.random() * max));
};
const solution = (a = []) => {
let len = a.length;
const t0 = performance.now();
let swapped = false;
do {
swapped = false;
for (let i = 1; i < len; i += 1) {
if (a[i] < a[i - 1]) {
[a[i], a[i - 1]] = [a[i - 1], a[i]];
swapped = true;
}
}
} while (swapped);
const t1 = performance.now();
console.log("time: ", t1 - t0);
return a;
};
const solution1 = (a = []) => {
let len = a.length;
let swapped = false;
const t0 = performance.now();
do {
swapped = false;
for (let i = 1; i < len; i += 1) {
if (a[i] < a[i - 1]) {
[a[i], a[i - 1]] = [a[i - 1], a[i]];
swapped = true;
}
}
len -= 1;
} while (swapped);
const t1 = performance.now();
console.log("time: ", t1 - t0);
return a;
};
const solution2 = (a = []) => {
let len = a.length;
const t0 = performance.now();
do {
let newLen = 0;
for (let i = 1; i < len; i += 1) {
if (a[i] < a[i - 1]) {
[a[i], a[i - 1]] = [a[i - 1], a[i]];
newLen = i;
}
}
len = newLen;
} while (len > 1);
const t1 = performance.now();
console.log("time: ", t1 - t0);
return a;
};
const a = getRandomArray(10000, 1000);
solution(a.slice());
solution1(a.slice());
solution2(a.slice()); Reference |
Tip:
let arr = [10, 80, 40, 60, 30, 90, 40, 50, 85];
const bubbleSort = (arr) => {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
};
const bubbleSortPlus = (arr) => {
let second_max_pos = 0; // 存储每次遍历的第二大数索引
for (let i = 0; i < arr.length - 1; i++) {
let j = second_max_pos; // 从每次遍历之后的第二大数的索引开始遍历
second_max_pos = 0; // 每次第二层遍历开始前重置
for (j; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
if (arr[j] > arr[second_max_pos]) {
second_max_pos = j;
}
}
}
}
};
bubbleSortPlus(arr); |
function bubbleSort1(array) {
//常规冒泡排序
for (let i = 0; i < array.length; i++) {
for (let j = i; j < array.length - 1; j++) {
if (array[j] > array[j + 1]) {
array[j + 1] = array[j + 1] ^ array[j]
array[j] = array[j + 1] ^ array[j]
array[j + 1] = array[j + 1] ^ array[j]
}
}
}
}
function bubbleSort2(array) {
//思路 :寻找每一次冒泡排序后最后一次交换的下标,减少排序次数
let i = array.length - 1;
while (i > 0) {
let index = 0
for (let j = 0; j < i; j++) {
if (array[j] > array[j + 1]) {
index=j
array[j + 1] = array[j + 1] ^ array[j]
array[j] = array[j + 1] ^ array[j]
array[j + 1] = array[j + 1] ^ array[j]
}
}
i = index;
}
}
let array = [1, 3, 2, 4, 11, 23, 3, 35, 7, 8,"2",'2',[5],(1),{"6":1}]
bubbleSort2(array)
console.log(array); 输出
[ 1, 1, 2, 2, 2, 3, 3, 4, 5, 7, 8, 11, 23, 35, { '6': 1 } ]
所以为啥??[5]不见了 |
// 优化版本
|
时间复杂度: n^2
The text was updated successfully, but these errors were encountered: