一、前言
这篇博客是转载的,但是为了加深理解和记忆,所以按自己的思路写了一遍代码。
附上参考博客:十大经典排序算法,里面有动图。
1.1算法归类
二、冒泡排序
/*
1.比较相邻的两个元素,如果前一个比后一个大(或者后一个比前一个小),就交换位置
2.对每一个相邻元素做同样的工作,从开始第一对到结尾最后一对,这样在最后的元素会是最大的数
3.需要重复n-1次上面的工作
*/
function bubbleSort(arr) {
let temp;
for(let i=0; i<arr.length-1; i++) {
for(let j=0; j<arr.length-1-i; j++) {
if(arr[j] > arr[j+1]) {
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
三、选择排序
/*
1.选中第一个位置,然后从未排序的元素中找出最小(最大)的一个放在该位置
2.经过n-1次的选择,完成排序
*/
function selectSort(arr) {
let minIndex;
let temp;
for(let i=0; i<arr.length-1; i++) {
minIndex = i;
for(let j=i+1; j<arr.length; j++){
if(arr[j] < arr[minIndex]) {
minIndex = j;
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
四、插入排序
/*
1.思想上:将数组分为两堆,一堆是排好序的,一堆是没排好序的
2.数组第一个元素可以被认为是排好序的,然后我们拿到数组第二个元素的值
3.比较第二个元素与第一个元素的大小,(假设从小到大排列),如果第二个元素小于第一个元素,则将第二个元素插入到第一个元素的前面,至此,完成一次插入。
4.此时形成了由第一个元素和第二个元素组成的有序数列,以及剩下的未排序数列
5.拿到数列第三个元素的值,用这个值从有序数列的末端开始向前逐个比较,然后插入到第三个值在有序数列中应该在的位置(与第3步同理)
6.继续拿值,重复比较与插入过程。
*/
function insertSort(arr) {
let pre_index;
let cur_num;
for(let i=1; i<arr.length; i++) {
cur_num = arr[i]; //拿到当前待比较值
pre_index = i - 1; //pre_index指向有序数列的末尾
while(pre_index >= 0 && cur_num < arr[pre_index]) {
arr[pre_index + 1] = arr[pre_index]; //pre_index指向的元素向后覆盖
pre_index--; //pre_index指针向前移动
}
arr[pre_index + 1] = cur_num //找到了cur_num应该在的位置(preindex + 1)
}
return arr;
}
五、归并排序
/*
核心思想:
1.对数组二分,然后利用递归思想逐步由下至上合并左右序列
2.合并数组时,先由左右有序序列合并得到另一个有序序列,然后将这个序列赋值到数组对应部分
*/
function sort(arr) {
let temp = []; //准备一个空数组
mergeSort(arr, 0, arr.length - 1, temp); //调用函数来排序
}
function mergeSort(arr, left, right, temp) {
if(left < right) {
let mid = Math.floor((left + right) / 2);
mergeSort(arr, left, mid, temp); //左序列二分
mergeSort(arr, mid+1, right, temp); //右序列二分
mergeArray(arr, left, mid, right, temp); //合并左右序列并使合并后得到的有序序列赋值到原数组对应部分
}
}
function mergeArray(arr, left, mid, right, temp) {
let i = left; //left不能作为指针动,后面要用,所以用i来接收left的值
let j = mid + 1; //right不能作为指针动,后面要用,所以用i来接收right的值
let t = 0; //t是临时数组指针
while(i <= mid && j <= right) {
if(arr[i] <= arr[j]) {
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}
while(i <= mid) { //将左边剩余元素依次填入temp
temp[t++] = arr[i++];
}
while(j <= right) { //将右边剩余元素依次填入temp
temp[t++] = arr[j++];
}
t = 0; //temp的指针重置
while(left <= right) { //将temp数组中的元素拷贝到原数组对应的部分
arr[left++] = temp[t++];
}
}
六、快速排序
function quickSort(arr, startIndex, endIndex) {
if(startIndex < endIndex) {
let pivotIndex = getPivotIndex(arr, startIndex, endIndex);
quickSort(arr, startIndex, pivotIndex);
quickSort(arr, pivotIndex + 1, endIndex);
}
}
//挖坑法
function getPivotIndex(arr, startIndex, endIndex){
let pivot = arr[startIndex];//先取第一个位置的元素作为基准元素
let left = startIndex; //左半部分指针
let right = endIndex; //右半部分指针
let index = startIndex; //坑的位置,初始等于pivot的位置
while(left <= right){
//先从右指针开始判断,right指针从右向左进行比较
while(left <= right){
if(arr[right] < pivot){ //如果当前元素小于基准元素
arr[index] = arr[right]; //用右边的值填补空位
index = right; //右边形成新的空位
left++; //left后移
break; //跳出循环,然后进入左边的判断
}
right--; //如果右边当前元素大于pivot,right指针左移
}
//left左边判断
while(left <= right){
if(arr[left] > pivot){ //如果当前元素大于基准元素
arr[index] = arr[left]; //右边填补空位
index = left; //左边形成新的空位
right--; //right前移
break; //跳出循环,进入右边判断
}
left++; //如果左边当前元素小于pivot,left指针右移
}
}
arr[index] = pivot; //找到基准元素该在的位置后赋值
return index;
}
//指针交换法:
function getPivotIndex(arr, startIndex, endIndex){
let left = startIndex; //左指针
let right = endIndex; //右指针
let index = startIndex; //基准元素位置
let pivot = arr[startIndex]; //基准元素的大小
//大循环
while(left < right){
//控制右指针左移,满足条件则进行循环,不满足则退出
while(left < right && arr[right] >= pivot){
right--;
}
//控制左指针右移,满足条件则进行循环,不满足则退出
while(left < right && arr[left] <= pivot){
left++;
}
//找到两个要交换的元素后,进行交换
if(left < right){
let temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
}
//left==right找到基准元素的位置后赋值
let temp = arr[left];
arr[left] = pivot;
arr[index] = temp;
return left;
}
七、计数排序
//计数排序基础版
function countSort(arr){
//1.得到序列的最大值
let max = arr[0];
for(let i=0; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
}
//创建数组,最大值为9,那么数组下标要到9,共10的数组长度
var countArray = new Array(max+1);
//数组赋值,不赋值均为undefined
for(let i=0; i<countArray.length; i++){
countArray[i] = 0;
}
//遍历原数组,并在统计数组中统计
for(let i=0; i<arr.length; i++){
countArray[arr[i]]++;
}
//遍历统计数组
let index = 0;
let sortedArray = new Array(arr.length);
for(let i=0; i<countArray.length; i++){
for(let j=0; j<countArray[i]; j++){
sortedArray[index++] = i;
}
}
return sortedArray;
}
//利用最大最小数设置偏移量:改良版计数排序
function countSort(arr){
//1.找到最大值与最小值
let min = arr[0], max = arr[0];
for(let i=0; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
if(arr[i] < min){
min = arr[i];
}
}
//2.创建一个统计数组
let countArray = new Array(max - min + 1);
for(let i=0; i<countArray.length; i++){
countArray[i] = 0;
}
//3.遍历原数组并统计 95 94 93 92
for(let i=0; i<arr.length; i++){
countArray[arr[i] - min]++;
}
//4.遍历统计数组赋值给新数组
let index = 0;
let sortedArray = new Array(arr.length);
for(let i=0; i<countArray.length; i++){
for(let j=0; j<countArray[i]; j++){
//实际值为最小值加偏移量
sortedArray[index++] = min + i;
}
}
return sortedArray;
}
//稳定的计数排序
function countSort(arr){
//1.找到最大最小值
let max = arr[0], min = arr[0];
for(let i=0; i<arr.length; i++){
if(arr[i] > max){
max = arr[i];
}
if(arr[i] < min){
min = arr[i];
}
}
//2.创建统计数组
let countArray = new Array(max - min + 1);
for(let i=0; i<countArray.length; i++){
countArray[i] = 0;
}
//3.遍历原数组并统计
for(let i=0; i<arr.length; i++){
countArray[arr[i] - min]++;
}
//4.优化统计数组:从第二个元素开始,每个元素都加上前面所有元素的值
// 优化的统计数组每个元素的值,代表下标所对应的数在sortedArray中最大位置
let sum = 0;
for(let i=0; i<countArray.length; i++){
sum += countArray[i];
countArray[i] = sum;
}
//5.倒序遍历原始数列,从统计数组中找到自己的正确位置,赋值到结果数组
let sortedArray = new Array(arr.length);
for(let i=arr.length-1; i>=0; i--){
sortedArray[countArray[arr[i] - min] - 1] = arr[i];
countArray[arr[i] - min]--;
}
return sortedArray;
}
var arr = [66,55,87,48,79,12,14,45,46,65,35,25,84,30,79,84,96,99,63,53,80];
arr = countSort(arr);
console.log(arr);
八、希尔排序
function shellSort(arr){
let len = arr.length;
let cur_num;
//增量从len/2开始,然后逐步缩减,直到增量为1
for(let gap=Math.floor(len/2); gap>0; gap=Math.floor(gap/2)){
//从第gap个数,逐个对每个数所在组进行插入排序
for(let i=gap; i<len; i++){
let j = i; //让j做游标,重置游标
cur_num = arr[i]; //记录当前数字
while(j-gap >= 0 && arr[j-gap] > cur_num){ //这个while似乎可以改成if
arr[j] = arr[j-gap];
j = j - gap;
}
arr[j] = cur_num;
}
}
}