7大排序算法
一、排序算法分类
1.外排序:需要在内外存之间多次交换数据
2. 内排序:只在内存中进行
插入排序类
直接插入排序
希尔排序
选择排序类
简单选择排序
堆排序
交换类排序类
冒泡排序
快速排序
归并排序类
归并排序
希尔排序时直接插入排序的升级版,堆排序和快速排序分别是简单选择排序和冒泡排序的升级版。
二、思想与实现
1.插入排序类
直接插入排序
思想:将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增加1的有序表
node.js实现
const readline=require('readline')const rl=readline.createInterface({ input:process.stdin, output:process.stdout })var arr=[] rl.on('line',(input)=>{ arr=input.split(/\s+/).map((item)=>{ return +item }) InsertSort(arr) rl.close() })function InsertSort(arr){ const len=arr.length for(let i=1;i<len;i++){ //如果即将插入的数比已排好序的最后一个数小,已排好需要移动 if(arr[i]<arr[i-1]){ let temp=arr[i] //对排好序的进行从后向前遍历,一旦发现要插入的数值大于已排好序中的某个记录,停止,那么就找到了要插入的位置 for(var j=i-1;arr[j]>temp&&j>=0;j--){ //已排好序的记录后移 arr[j+1]=arr[j] } //将要插入的数值插入 arr[j+1]=temp } } console.log(arr) }
希尔排序
思想:将相距某个’增量‘的记录组成一个子序列,在子序列内部进行直接插入排序,当增量为1时,列表便有序了
//希尔排序,是直接插入排序的升级版//思想将相距某个’增量‘的记录组成一个子序列,在子序列内部进行直接插入排序,当增量为1时,列表便有序了const readline = require('readline');const rl = readline.createInterface({ input: process.stdin, output: process.stdout });var inputArr = []; rl.on('line', function (input) { inputArr=input.split(/\s+/) inputArr=inputArr.map((item)=>{ return +item }) ShellSort(inputArr) inputArr=[] rl.close() });function ShellSort(arr){ var len=arr.length if(len<1)return var incement=len while(incement>1){ incement=Math.ceil(incement/3)//增量序列 for(var i=incement;i<arr.length;i++){ //将arr[i]插入增量序列 if(arr[i]<arr[i-incement]){ var key=arr[i] //向后看,看的步长是incement,如果当前要插入的比前面的小,那么前面的需要后移 for(var j=i-incement;j>=0&&arr[j]>key;j-=incement){ arr[j+incement]=arr[j] } //直到要插入的比前面的大,找到位置插入 arr[j+incement]=key } } } console.log(arr) }
2.选择排序类
简单选择排序
思想:每趟从n-i(i=0,1,...n-1)个记录中选出最小的那个关键字作为有序序列的第i个记录
//简单排序的思想:每趟从n-i(i=0,1,...n-1)个记录中选出最小的那个关键字作为有序序列的第i个记录。const readline=require('readline')const rl=readline.createInterface({ input:process.stdin, output:process.stdout })var arr=[] rl.on('line',(input)=>{ arr=input.split(/\s+/).map((item)=>{ return +item }) SelectSort(arr) rl.close() })function SelectSort(arr){ const len=arr.length if (len<1)return for(let i=0;i<len-1;i++){ let min=i for(let j=i+1;j<len;j++){ if(arr[min]>arr[j]){ min=j } } if(min!=i){ let t=arr[min] arr[min]=arr[i] arr[i]=t } } console.log(arr) }
堆排序
思想:将待排序列构造成一个大顶堆(小顶堆)。将根节点移走(与最后一个节点互换),对剩余的元素重新构造一个大顶堆,然后再移走根节点,如此反复。
//堆排序算法思想//将待排序列构造成一个大顶堆(小顶堆)。将根节点移走(与最后一个节点互换),对剩余的元素重新构造一个大顶堆,然后再移走根节点,如此反复。const readline = require('readline');const rl = readline.createInterface({ input: process.stdin, output: process.stdout });var inputArr = []; rl.on('line', function (input) { inputArr=input.split(/\s+/) inputArr=inputArr.map((item)=>{ return +item }) HeapSort(inputArr) inputArr=[] rl.close() }); function HeapSort(arr){ var len=arr.length if(len<1)return //建堆 for(let i=Math.floor(len/2)-1;i>=0;i--){ HeapAdjust(arr,i,len-1) } //交换第一个和最后一个,调整堆 for(let i=len-1;i>0;i--){ swap(arr,0,i) HeapAdjust(arr,0,i-1) } console.log(arr) }//adjnum需要调整的下标,len最大下标(总长度-1)//调整arr[adjnum],使得[adjnum,len]为大顶堆function HeapAdjust(arr,adjnum,len){ var temp=arr[adjnum] for(var j=2*adjnum+1;j<=len;j=j*2+1){ if(j<len&&arr[j]<arr[j+1]){ j++//j是较大关键字的下标 } if(temp>arr[j]){ break } arr[adjnum]=arr[j]//较大关键字放在父亲节点上 adjnum=j } arr[adjnum]=temp//相当于最大点和父亲节点交换}function swap(arr,low,high){ var t=arr[low] arr[low]=arr[high] arr[high]=t }
3.交换排序类
冒泡排序
思想:两两比较相邻记录
法一
// 冒泡排序的思想,两两比较相邻记录const readline = require('readline');const rl = readline.createInterface({ input: process.stdin, output: process.stdout });var inputArr = []; rl.on('line', function (input) { inputArr=input.split(/\s+/) inputArr=inputArr.map((item)=>{ return +item }) BubbleSort(inputArr); inputArr=[] rl.close() });function BubbleSort(list_num){ let len=list_num.length if (len<1) return for(let i=0;i<len;i++){ for(let j=len-1;j>i;j--){ if(list_num[j]<list_num[j -1]){ let t=list_num[j]; list_num[j]=list_num[j-1]; list_num[j-1]=t; } } } console.log(list_num) // rl.write(list_num.join(' '));write第一个参数表示输出的数据,必须是字符串类型}
法二
// 冒泡排序的思想,两两比较相邻记录const readline = require('readline');const rl = readline.createInterface({ input: process.stdin, output: process.stdout });var inputArr = []; rl.on('line', function (input) { inputArr=input.split(/\s+/) inputArr=inputArr.map((item)=>{ return +item }) BubbleSort(inputArr); inputArr=[] rl.close() });function BubbleSort(list_num){ let len=list_num.length let flag=true if (len<1) return for(let i=0;i<len&&flag;i++){ flag=false for(let j=len-1;j>i;j--){ if(list_num[j]<list_num[j -1]){ let t=list_num[j]; list_num[j]=list_num[j-1]; list_num[j-1]=t; flag=true } } } console.log(list_num) // rl.write(list_num.join(' '));write第一个参数表示输出的数据,必须是字符串类型}
快速排序
思想:通过一趟排序,将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序的目的
法一
//快速排序的思想//通过一趟排序,将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,//则可分别对这两部分记录继续进行排序,已达到整个序列有序的目的const readline=require('readline')const rl=readline.createInterface({ input:process.stdin, output:process.stdout })var arr=[] rl.on('line',(input)=>{ arr=input.split(/\s+/).map((item)=>{ return +item }) QuickSort(arr) // Partition(arr,0,arr.length-1) rl.close() })//对整个序列进行快速排序function QuickSort(arr){ Qsort(arr,0,arr.length-1) console.log(arr) }//对[low...high]之间的序列进行快速排序function Qsort(arr,low,high){ if(low<high){ var pivot=Partition(arr,low,high)//将arr[low..high]一分为二,返回一分为二的枢纽所在位置 Qsort(arr,pivot+1,high)//对高子递归表排序 Qsort(arr,low,pivot-1)//对低子递归表排序 } }function Partition(arr,low,high){ var pivotkey=arr[low] while(low<high){ while(low<high&&arr[high]>pivotkey) high-- swap(arr,low,high) while(low<high&&arr[low]<pivotkey) low++ swap(arr,low,high) } return low // console.log(arr)}function swap(arr,low,high){ var t=arr[low] arr[low]=arr[high] arr[high]=t }
法二
//快速排序的思想//通过一趟排序,将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,//则可分别对这两部分记录继续进行排序,已达到整个序列有序的目的//优化:1、枢纽关键字选取,使用左中右取三者中间值作为关键字枢纽。2、减少不必要的交换,使用替换//对于小数组,使用直接插入排序会更高const readline=require('readline')const rl=readline.createInterface({ input:process.stdin, output:process.stdout })var arr=[] rl.on('line',(input)=>{ arr=input.split(/\s+/).map((item)=>{ return +item }) QuickSort(arr) // Partition(arr,0,arr.length-1) rl.close() })//对整个序列进行快速排序function QuickSort(arr){ Qsort(arr,0,arr.length-1) console.log(arr) }//对[low...high]之间的序列进行快速排序function Qsort(arr,low,high){ if(low<high){ var pivot=Partition(arr,low,high)//将arr[low..high]一分为二,返回一分为二的枢纽所在位置 Qsort(arr,pivot+1,high)//对高子递归表排序 Qsort(arr,low,pivot-1)//对低子递归表排序 } }function Partition(arr,low,high){ //优化关键字枢纽,将中间值赋给arr[low] var m=low+parseInt((high-low)/2) if(arr[low]>arr[high]) swap(arr,low,high) if(arr[m]>arr[high]) swap(arr,m,high) if(arr[m]>arr[low]) swap(arr,m,low) //此时low已经是三者的中间值了 var pivotkey=arr[low] var temp=pivotkey//备份中间枢纽 while(low<high){ while(low<high&&arr[high]>pivotkey) high-- arr[low]=arr[high] while(low<high&&arr[low]<pivotkey) low++ arr[high]=arr[low] } arr[low]=temp return low // console.log(arr)}function swap(arr,low,high){ var t=arr[low] arr[low]=arr[high] arr[high]=t }
4.归并排序类
归并排序
思想:把原序列分成两个长度为n/2的子序列,对这两个子序列分别进行归并排序,最后把两个排好序的子序列合并成一个最终的派系序列
//归并排序//把原序列分成两个长度为n/2的子序列,对这两个子序列分别进行归并排序,最后把两个排好序的子序列合并成一个最终的派系序列const readline = require('readline')const rl = readline.createInterface({ input: process.stdin, output: process.stdout })var arr = [] rl.on('line', (input) => { arr = input.split(/\s+/).map((item) => { return +item }) console.log(MergeSort(arr)) // Partition(arr,0,arr.length-1) rl.close() })function MergeSort(arr) { var len = arr.length; if (len < 2) return arr //递归,当长度为1时此处必须返回arr,然后再逐层合并 var middle = Math.floor(len / 2), l = arr.slice(0, middle), r = arr.slice(middle); return merge(MergeSort(l), MergeSort(r)) // console.log(x)}function merge(l,r){ var result=[] while(l.length&&r.length){ if(l[0]<=r[0]){ result.push(l.shift()) }else{ result.push(r.shift()) } } if(l.length){ result.concat(l) } if(r.length){ result.concat(r) } return result }
三、复杂度及稳定性
四、注意事项
编程要考虑全面,首先判断输入的参数是否是空,再者如果不确定输入的类型,要做类型检测
参考资料
大话数据结构-程杰著
作者:fenerchen
链接:https://www.jianshu.com/p/a957396c2bf3
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦