一、稳定性
官方定义: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
白话: 指的是排序之后,相同元素的相对位置有没有发生变化,如果变化了,就不稳定,如果没有变化,则相对稳定
举个例子就是:
比如:[12,3,15,12,35,34,6],使用冒泡排序的话,从大到小排序后为
[35,34,15,12,12,6,3],两个12的相对位置没有改变,所以相对稳定,如果使用快速排序,如果小于等于12,就放在12后边,那么两个12的相对位置就发生了改变,就不是很稳定!
二、各种排序算法复杂度
三、各种算法实现
稳定排序
1、冒泡排序
数组原型上追加冒泡排序方法
// 冒泡排序 从大到小排序 倒序/顺序
Array.prototype.Maopao = function (sort = false) {
var arr=this;
if(arr.length<=1){
return arr;
}
for (var i = 0; i < arr.length - 1; i++) {//第几轮
for (var k = 0; k < arr.length - 1 - i; k++) {//相邻的两个元素
//从小到大
if (sort == false) {
if (arr[k] > arr[k + 1]) {
temp = arr[k];
arr[k] = arr[k + 1];
arr[k + 1] = temp;
}
}
//从大到小
else {
if (arr[k] < arr[k + 1]) {
var temp = arr[k];
arr[k] = arr[k + 1];
arr[k + 1] = temp;
}
}
}
}
return arr;
}
var arr2 = [18, 3, 1, 26, 7, 33, 6, 11];
arr2.Maopao();
通过构造函数写
function ArrayList(){
this.array=[];
//数据插入
ArrayList.prototype.insert=function(item){
this.array.push(item);
}
//冒泡排序
ArrayList.prototype.maopao=function(){
var length = this.array.length;
for(var i=0;i<length-1;i++){
for(j=0;j<length-1-i;j++){
if(this.array[j]<this.array[j+1]){
var temp=this.array[j];
this.array[j]=this.array[j+1];
this.array[j+1]=temp;
}
}
}
console.log(this.array)
return this.array;
}
}
var arrs=new ArrayList();
arrs.insert(34);
arrs.insert(3);
arrs.insert(6);
arrs.insert(4);
arrs.maopao();
2、插入排序
思想
插入排序与选择排序的区别
1、选择排序
首先在未排列的数组中找到最大/小值,存放到数组的起始序列,紧接着在剩下的数组中找到次大/小的值,递归进行
2、插入排序
类似于扑克牌,默认先插第一个元素,然后下一个元素如果比他大,就放在后面,如果比他小,就放在前面 冒泡
对于未排序数据,在已排序序列中从后向前扫描,找到相应位置
//插入排序
Array.prototype.InsertSort = function () {
var arr = this;
for (var i = 0; i < arr.length; i++) {
var temp = arr[i];//标记值
var j = i - 1;//默认已排序的元素
//如果前面的值比后面的大,两个元素就交换一下位置
while (j >= 0 && arr[j] > temp) {
arr[j + 1] = arr[j];
j--;//这里一定得记得!!!
}
arr[j + 1] = temp;
}
return arr;
}
var arrs = [1, 6, 3, 2, 45, 66, 34, 21];
arrs.InsertSort();
console.log(arrs);
//二分法 折半查找 标记值 左、右
//排好序 》左边找 《右边找 前提!!!!数组是有序的
Array.prototype.binaryInsertSort=function(start,end,key){
var arr=this;
if(start>end){
return false;
}
var mid=Math.floor((end+start)/2);
if(arr[mid]==key){
return mid;
}
else if(arr[mid]>key){
return arr.binaryInsertSort(start,mid-1,key);
}
else {
return arr.binaryInsertSort(mid+1,end,key);
}
return false;
};
var arrs = [1, 2, 6, 45, 66, 74, 91];
console.log(arrs.binaryInsertSort(0,arrs.length,91));
3、归并排序
含义:什么是归并排序?
归并排序是将两个有序的数列合并成一个大的有序的数列,通过递归进行,层层合并,进行归并
先分再合并
function MergeSort(array) {
//分
let len = array.length;
if (len <= 1) {
return array;
}
let num = Math.floor(len / 2);
let left = MergeSort(array.slice(0, num));
let right = MergeSort(array.slice(num, array.length));
return merge(left, right);
//归并
function merge(left, right) {
//记录result的索引 l和r是一样的意思 为了保持索引能够连着
let [l, r] = [0, 0];
let result = [];
while (l < left.length && r < right.length) {
if (left[l] < right[r]) {
result.push(left[l]);
l++;
} else {
result.push(right[r]);
r++;
}
}
//归并
result = result.concat(left.slice(l, left.length));
result = result.concat(right.slice(r, right.length));
return result;
}
}
var arr = [80, 34, 56, 25, 27, 85, 32];
console.log(MergeSort(arr));
function MergeSort(array){
if(array.length<=1){
return array;
}
var mid=Math.floor(array.length/2);
var left=MergeSort(array.slice(0,mid));
var right=MergeSort(array.slice(mid));
return Merge(left,right);
// 合并
function Merge(left,right){
var result=[];
while(left.length&&right.length){
if(left[0]>right[0]){
//删除并返回
result.push(right.shift());
}
else {
result.push(left.shift());
}
}
//左右合并
return result.concat(left, right);;
}
}
var arr = [80, 34, 56, 25, 27, 85, 32];
console.log(MergeSort(arr));
不稳定排序
4、快速排序
思想
以数组中的某一个值为标记量,遍历数组,如果数组的长度小于等于1的话,直接返回该数组,
否则遍历的值比该标志量小,那么就把他压入a数组中,否则,压入b数组中,递归的进行这样的操作,就把排序结果搞出来了
左、右、中间 递归排序
需要对数组的数量进行判断,如果长度小于等于1,就返回该数组,判断条件写在最前面
Array.prototype.QuickSort = function () {
var arr = this;
if (arr.length <= 1) {
return arr;
}
var middle = arr.splice(parseInt(arr.length / 2), 1);
var left = [];//小
var right = [];//大
for (var i = 0; i < arr.length; i++) {
if (arr[i] < middle) {
left.push(arr[i]);
}
else {
right.push(arr[i]);
}
}
return left.QuickSort().concat(middle).concat(right.QuickSort())
}
var arr = [1, 2, 22, 32, 23, 12, 34];
arr.QuickSort();
console.log(arr,arr.QuickSort());
5、选择排序
思想
插入排序与选择排序的区别
1、选择排序
首先在未排列的数组中找到最大/小值,存放到数组的起始序列,紧接着在剩下的数组中找到次大/小的值,递归进行
2、插入排序
类似于扑克牌,默认先插第一个元素,然后下一个元素如果比他大,就放在后面,如果比他小,就放在前面 冒泡
对于未排序数据,在已排序序列中从后向前扫描,找到相应位置
Array.prototype.SelectSort=function(){
var arr=this;
if(arr.length<=1){
return arr;
}
for(var i=0;i<arr.length;i++){//第几轮 主要比较的对象 第i个元素
for(var k=i+1;k<arr.length;k++){//与第i个元素后面的元素进行比较
if(arr[i]<arr[k]){
var temp=arr[i];
arr[i]=arr[k];
arr[k]=temp;
}
}
}
return arr;
}
var arrs=[1,6,3,2,45,66,34,21];
arrs.SelectSort();