- 冒泡排序
- 选择排序
- 插入排序
- 归并排序
- 计数排序(counting sort)
- 基数排序(radix sort)
- 希尔排序
- 堆排序
- 桶排序
先行条件
构造一个数组列表函数
function ArrayList(){
this.array=[];
//插入元素
ArrayList.prototype.insert=function(item){
this.array.push(item);
}
//以字符串输出数组列表元素
ArrayList.prototype.toString=function(){
return this.array.join("-");
}
}
var list = new ArrayList(); //实例化
list.insert(3);
list.insert(6);
list.insert(4);
list.insert(2);
list.insert(84);
list.insert(966);
list.insert(487);
//交换两个位置的数据
ArrayList.prototype.swap = function (pos1, pos2) {
let temp = this.array[pos1];
this.array[pos1] = this.array[pos2];
this.array[pos2] = temp;
}
冒泡排序 Bubble sort
对未排序的元素从头到尾依次比较相邻两个元素的关系
ArrayList.prototype.buubleSort = function () {
//获取数组长度
let length = this.array.length;
for (let j = length - 1; j >= 0; j--) {
for (let i = 0; i < j; i++) {
if (this.array[i] > this.array[i + 1]) {
this.swap(i, i + 1);
}
}
}
}
console.log(list.toString())
list.buubleSort();
console.log(list.toString())
排序前:3-6-4-2-84-966-487
排序后:2-3-4-6-84-487-966
比较次数
大O表示法
公式:N*(N-1)/2
交换次数
大O表示法
公式:N*(N-1)/4
选择排序Select sort
选定第一个索引位置,依次跟后面的元素依次比较
如果后面的元素小于第一个索引的元素,则交换位置
经过一轮比较后就可以确认第一个位置是最小的
然后再使用同样的方法把剩下的元素比较
ArrayList.prototype.selectSort=function(){
let length=this.array.length //获取数组列表长度
//遍历数组的每一项元素
//length-1 就是数组的最后一项,而最后一项不用比较的,因为已经排序过了
for(let j=0;j<length-1;j++){
let min=j; //定义变量min存储里层循环获取到的最小元素索引
/*
再次遍历数组元素 初始值等于min+1 因为外层循环的时候会把min等于外层循环索引
而外层循环当前索引是不用在里层循环遍历的 之前的元素已经正确的排号位置了 所以直接跳过
j
4 9 5 6 81 2
m
i
*/
for(let i=min+1;i<length;i++){
if(this.array[min]>this.array[i]){ //比较min索引的元素和遍历的每一个元素 哪个大
min=i; //如果Min>里层遍历的元素 就把里层当前循环的索引赋值给min
}
}
this.swap(min,j); //交换元素
}
}
list.selectSort();
console.log(list.toString());
结果输出:2-3-4-6-84-487-966
比较字数
大O表示法
公式:N*(N-1)/2
交换次数
大O表示法
公式:N-1
插入排序 Insert sort
插入排序的核心是局部有序
在一个数组中 选择其中一个作为标记元素
被标记元素左边所有元素已经排好顺序
意味着有一部分已经排好序,还有一部分是没有排序的
ArrayList.prototype.insertSort=function(){
let length=this.array.length; //获取数组长度
/*
遍历数组里的每一个元素 从1开始,因为要示左边为以排序好,选择元素插入到左边排序好的位置
*/
for(let i=1;i<length;i++){
let j=i; //j 算是一个指针 指遍历左边排序好的元素
let temp=this.array[i] //temp 存储当前循环索引位置的元素数据
//用while循环 因为不知道插到哪个位置
//循环的条件是 如果数组j-1就是上一个元素大于temp(是当前循环索引位置的元素数据) 就执行循环体的指令
while(this.array[j-1]>temp&&j>0){
//把当前循环索引位置的元素数据换成上一个元素数据
//例如:6 3 9 2 i=3 temp=3 j=3 j-1=6 j=j-1 就是j=6
this.array[j]=this.array[j-1];
//指针指向上一个元素
j--
}
//插入temp的数据到j的位置
this.array[j]=temp;
}
}
比较次数
公式:N*(N-1)/4
大O表示法:
复制次数
公式:N*(N-1)/2
希尔排序 Shell’s Sort
是插入排序的一种高效的进化版,并且效率比插入排序更快
通过指定的间隔来交换数组元素,尽量让最小的排到最前面,最后的尽量排到后面
间隔选择 Shell原稿
N / 2 N=数组长度
如果N=100 向下取整
100/2=50 50/2=25 25/2=12 12/2=6 6/2=3 3/2=1
ArrayList.prototype.ShellSort = function () {
let length=this.array.length; //获取数组长度
let gap=Math.floor(length/2); //间隔增量 为数组的长度除以2
//循环,只要gap大于或者等于1 就执行循环体内的指令
while(gap>=1){
//遍历数组的每一个元素
for(let i=gap;i<length;i++){
let j=i; //把i复制给j j相当于指针
let temp=this.array[i]; //把i的元素复制给temp 因为等一下i的元素会变
/*
循环,当j-gap大于temp的时候 j一开始是和gap相等,j-gap=0 如果索引为0的元素大于temp
以及j>gap-1 这是为了防止越界
*/
while(this.array[j-gap]>temp&&j>gap-1){
//就把j-gap的元素给j 执行到这里说明j-gap索引的元素大于j的元素 所以要调换位置 把大放到右边
this.array[j]=this.array[j-gap];
//j重新赋值 向左退gap步
j-=gap;
}
this.array[j]=temp;
}
//每次gap都除以2 向下取整
gap=Math.floor(gap/2);
}
}
例子:数组元素 [2 6 4 3 84 966 487]
0 1 2 3 4 5 6
2 6 4 3 84 966 487
let gap=Math.floor(length/2);
gap=7/2 3.5向下取整3
while(gap>=1)
while循环当gap<1的时候停止
for(let i=gap;i
let j=i;
每次循环都生命一个 j 指针变量 初始化为i j是用来向gap的左边递减寻找上一个gap的
let temp=this.array[i];
以及temp变量,存储 i 的元素值 因为等一下交换了元素后 i的值可能会变
while(this.array[j-gap]>temp){
this.array[j]=this.array[j-gap];
}
循环当数组的j-gap索引位置的元素 大于 temp 的时候就把j-gap的元素赋值给j
j-=gap;
每次j-=gap 相当于往左边进gap步 以到达下一个gap
this.array[j]=temp
最内层循环结束后就就把temp赋值给j
再次执行遍历循环
gap=Math.floor(gap/2);
遍历循环结束后 每次gap/2 向下取整 直到gap<=1就跳出循环
然后再次执行最外层while循环
快速排序Quick sort
重要的思想:分而治之
ArrayList.prototype.quickSort = function (arr) {
let length = arr.length; //获取数组的长度
//如果数组的长度小于1 就不用排序,直接返回数组
if (length <= 1) {
return arr;
}
let left = []; //存放小于基准的元素
let right = []; //存放大于基准的元素
let povit = arr[0]; //基准选取数组的一个元素
//遍历数组的每一个元素
for (let i = 1; i < length; i++) {
//小于基准的就放到left数组
if (arr[i] < povit) {
left.push(arr[i]);
} else {
//大于基准的就放到right数组
right.push(arr[i]);
}
}
//递归调用方法
//因为方法返回的是排序后数组 所以用排序后 小于基准的数组 合并 基准元素 以及排序后 大于基准的元素数组
return this.quickSort(left).concat(povit, this.quickSort(right));
}
平均效率
大O表示法:O(N*logN)