让每一个值进行”车轮战”, 失败即停, 下位”选手”继续, 成功就不停, 车轮战战到最后, 排出最正确的 从小到大 或者 从大到小 的顺序
比如 一个简单五位数字的数组
我们可以设置一个for循环来获取每个值
设置一个变量代表数组, 不同的语言有不同的写法, 以下以JS为例
let numberArray=[1,3,2,5,4];
比如, 我们要想争抢谁最大(从小到大的排序), 可以写以下内容
if(index1>index2){
//如果比下一位大, 跟它换位置
let max=index1;//将大值赋给max
let min=index2;//将小值赋给min
index1=min;//让下标在前的(小下标), 等于小值
index2=max;//让下标在后的(大下标), 等于大值
}
/*如何验证这个if的作用, 我们可以假设两组数据, [1,3],[4,2],
我们发现,
1和3比, 没有3大, 直接无法进入if判断, 最大值在后面
4和2比, 会被调换位置, 变成 [2,4], 也是大值在后面
这样一来, 我们让从小到大的基础判断就做好了
*/
添加第一层循环
让 最大或者最小的值 排到最后, 设置一个循环, 从index 0 到 数组的长度 -1
for (var innerLoopIndex= 0; innerLoopIndex < numberArray.length-1;innerLoopIndex++){
console.log(innerLoopIndex);
/*依次打印 0,1,2,3,4 长度虽然是5, 但是下标index从0开始, 到3就会结束
总共进行4次对比, 因为第四次对比已经是第四位元素(index3)和第五位元素(index4)对比
}
结合上面的if判断, 写出以下方法
let numberArray=[1,3,2,5,4];
for (var innerLoopIndex= 0; innerLoopIndex < numberArray.length-1;innerLoopIndex++){
if(numberArray[innerLoopIndex]>numberArray[innerLoopIndex+1]){
let max=numberArray[innerLoopIndex];//将大值赋给max
let min=numberArray[innerLoopIndex+1];//将小值赋给min
numberArray[innerLoopIndex]=min;//让下标在前的(小下标), 等于小值
numberArray[innerLoopIndex+1]=max;//让下标在后的(大下标), 等于大值
}
}
/*数组[1,3,2,5,4];
第一次, 下标0和下标1的值对比, 不进if, 因为1没3大
第二次, 下标1和下标2的值对比, 进if, 换位置, 数组发生变化,
[1,2,3,..] 3和2调换位置, 3打赢了车轮战, 变成index2
第三次, 下标2和下标3的值对比, 不进if, 因为3没5大
第四次, 下标3和下标4的值对比, 进if, 换位置, 数组发生变化
[...,4,5] 5和4调换位置, 5打赢了车轮战, 变成index4
*/
我们发现, 这一个for循环后, 数组已然成功排序 [1,2,3,4,5], 那么我们的方法完善了吗, 我们多输入几个数组来验证
例如: numberArray2=[6,7,5,3,4,2]
我们发现, 经过我们的循环之后, 数组的顺序仍然不是按照从小到大的顺序排的, 这是因为, 我们内循环, 每次仅排出一位选手, 比如这次, 结果是
console.log(numberArray2);
//打印 [6,5,3,4,2,7]
其实它仅仅排出了”第一名”, 我们现在就来观看下变化的过程 (第一轮战斗)
//[6,7,5,3,4,2]
/*第一次, 6和7比, 没有进入if, 数组不变化
第二次, 7和5比, 7大, 进入if, 调换位置, 数组发生变化
[6,5,7...], 7和5的位置调换,7打赢了战斗, 变成index2
第三次, 7和3比, 7大, 进入if, 调换位置, 数组发生变化
[...3,7...], 7和3的位置调换,7打赢了战斗, 变成index3
第四次, 7和4比, 7大, 进入if, 调换位置, 数组发生变化
[...4,7...], 7和4的位置调换,7打赢了战斗, 变成index4
第四次, 7和2比, 7大, 进入if, 调换位置, 数组发生变化
[...2,7], 7和2的位置调换,7打赢了战斗, 变成index5
*/
//结果[6,5,3,4,2,7]
当我们想要排出所有的顺序, 其实就需要每个数字争抢第二名, 第三名, 我们可以添加外层循环, 控制第二轮战斗, 第三轮战斗, …直到排出你想要的顺序, 仍然以第一次数组为例, 我们已经排出第一名了
第一轮战斗: 其实它仅仅排出了”第一名”, 我们现在就来观看下变化的过程 (第一轮战斗)
即排出第二名需要什么, 需要让”争夺第一的失败数字”参加第二次战斗
let numberArray=[6,7,5,3,4,2];
**for(var outerLoopIndex=0;outerLoopIndex<2,outerLoopIndex++){**
for (var innerLoopIndex= 0; innerLoopIndex < numberArray.length-1;innerLoopIndex++){
if(numberArray[innerLoopIndex]>numberArray[innerLoopIndex+1]){
let max=numberArray[innerLoopIndex];//将大值赋给max
let min=numberArray[innerLoopIndex+1];//将小值赋给min
numberArray[innerLoopIndex]=min;//让下标在前的(小下标), 等于小值
numberArray[innerLoopIndex+1]=max;//让下标在后的(大下标), 等于大值
}
}
}
/*我们在最外层又增添了一个循环, 我们通过查看循环参数和结束循环条件, 发现一共可以循环两次
第一次, outerLoopIndex=0, 满足循环条件, 第二次, outerLoopIndex=1, 仍然满足条件, 当第二次后
outerLoopIndex++之后就变成了2, outerLoopIndex也就是2并不满足循环条件 "<2"小于2, 不能进入第三次循环
我们刚才说了, 外层循环控制战斗的轮数, 我们打断点来检查是否是这样的
当outerLoopIndex=0, 满足循环条件, 进入外层循环的执行层, 也就是外面for循环的里面, 我们可以看到
是另一个for循环, 也就是内层循环, 进入循环, 然后查看变量变化
下标为0的和下标为1的进行判断, 不满足
下标为1的和下标为2的....
我们发现, 这和之前看到的重复了, 也就是我们所说的 "第一轮"战斗
我们跳过这个块, 进入下一次外层循环, 第二次外层循环之前, 我们的数组已经发生变化,即
[6,5,3,4,2,7]
然后代入第二次外循环, 又是重复从index0开始比较
第二次外循环的第一次内循环, index0和index1比较, 6比5大, 满足判断条件, 进入if, 调换位置
6成为index1, 5成为index0, 数组变化为 [5,6...]
二外二内次, index1和index2比, 6>3 仍然满足条件, 进入if, 调换位置, 6成为index2,
3成为index1, 数组变化为 [5,3,6...]
二外三内次, index2和index3比, 6>4 仍然满足条件, 进入if, 调换位置, 6成为index3,
4成为index2, 数组变化为 [...4,6...]
二外四内次, index3和index4比, 6>2 仍然满足条件, 进入if, 调换位置, 6成为index4,
3成为index3, 数组变化为 [...2,6...]
二外五内次, index4和index5比, 6<7 不满足条件
经过多次的第二次外循环的内循环后, 我们发现, 数组最终为
[5,3,4,2,6,7]
也就是说, 第二次的外循环, 我们排出了第二名
*/
我们说外层的循环控制的是”车轮战”的场次, 一共N场, 分别争抢 第一名, 第二名…第N名, 我们可以通过多次检查来判断代码是否符合说法, 这次, 我们将外循环跳转为循环数组的长度次, 即排出所有的名次
let numberArray=[6,7,5,3,4,2];
for(var outerLoopIndex=**0**;outerLoopIndex<**numberArray.length-1**,outerLoopIndex++){
for (var innerLoopIndex= 0; innerLoopIndex < numberArray.length-1;innerLoopIndex++){
if(numberArray[innerLoopIndex]>numberArray[innerLoopIndex+1]){
let max=numberArray[innerLoopIndex];//将大值赋给max
let min=numberArray[innerLoopIndex+1];//将小值赋给min
numberArray[innerLoopIndex]=min;//让下标在前的(小下标), 等于小值
numberArray[innerLoopIndex+1]=max;//让下标在后的(大下标), 等于大值
}
}
}
/* 第一轮战斗分出第一名, 第二轮分出第二名, 我们先忽略, 看看每轮执行的结果是否符合预期
第一轮[6,5,3,4,2,7]
第二轮[5,3,4,2,6,7]
第三轮[3,4,2,5,6,7]
第四轮[3,2,4,5,6,7]
第五轮[2,3,4,5,6,7]
第六轮[2,3,4,5,6,7]
我们会发现, 当第五轮之后, 其实所有的值都和index0比过了, 即第五轮过后, index0已经是最小值
没有必要再让它和其他值对比, 而不同长度不同数量的数组怎么判断这个"第五轮", 其实就是长度-1轮
所以我们可以控制外层循环次数为 长度-1次, 但是由于我们的外层循环index是从0开始的, 那么我们的
循环条件可以写为
**for(var outerLoopIndex=0;outerLoopIndex<numberArray.length-1,outerLoopIndex++)**
亦或者
**for(var outerLoopIndex=1;outerLoopIndex<numberArray.length,outerLoopIndex++)**
我们如果代入进每次的内循环会发现, 除了第一轮, 之后的每一轮好像都让我们的"选手"再次受伤,
明明第一次已经产生"第一名"了, 但是除了第一轮外的每一轮, 后续"选手"还和已经获得名次的选手匹配,
以下是"赛事记载":
第一轮, 没有名次, 值7在战斗多次后成功获得第一名的名次
但是第二轮的时候, 值6仍和第一名值7打
第三轮, 值5 仍和 有名次的 6,7打
第四轮, 值4 仍和 有名次的 5,6,7打
第五轮, 值3 仍和 有名次的 4,5,6,7打
*/
所以, "为了维护已得到名次的值的名誉, 为了保护弱小的值不再受伤", 我们决定剔除 "数组长度-1轮"和 "再次对比已有名次的值", 本次武林大赛, 做出以下更新;
于是乎, 编码更新如下
let numberArray=[6,7,5,3,4,2];
for(var outerLoopIndex=**0**;outerLoopIndex<**numberArray.length-1**,outerLoopIndex++){
for (var innerLoopIndex= 0; innerLoopIndex < numberArray.length-**outerLoopIndex**-1;innerLoopIndex++){
if(numberArray[innerLoopIndex]>numberArray[innerLoopIndex+1]){
let max=numberArray[innerLoopIndex];//将大值赋给max
let min=numberArray[innerLoopIndex+1];//将小值赋给min
numberArray[innerLoopIndex]=min;//让下标在前的(小下标), 等于小值
numberArray[innerLoopIndex+1]=max;//让下标在后的(大下标), 等于大值
}
}
}