作为一个程序设计人员,必须要懂算法和数据结构,这是每个毕业生必备的知识,最近在复习排序算法,进行全部的总结和介绍,但愿可以给学习排序算法的有所帮助,其中会有java和JavaScript的代码进行介绍。
一、十大排序算法
首先从一张大图来了解这十种排序算法的基本认识和比较,主要从时间复杂度和空间复杂度来介绍,图片是网上找的,不是自己做的。
1.冒泡排序算法
1).算法简介:看名字就能体会到他的原理,冒泡算法即冒泡泡,常识知道水中最小的泡泡会冒到最顶端,即总在这个算法中最小的数浮在上面。
2).基本思想:每次比较两个相邻的元素,如果它们的顺序错误就把它们交换过来,但是这个排序要走访所有的元素。最差的可能就是逆序(但可以写一个逆序方法解决),最好的情况就是顺序排好(不用排序)。
3).算法描述:
1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
3、针对所有的元素重复以上的步骤,除了最后一个。
4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
4).举例说明:对{12,25,8,36,9}这5个数从大到小排序。
首先明确,从大到小,就是最小的在最后面。然后进行排序演示:首先比较最前面的两个数,12和25,12<25,即12在25的后面,第一次排序后为: 25, 2,8, 36, 9,第二次比较: 2<8,顺序不正确,进行交换,得到第二次排序: 25, 8, 2, 36, 9,
第三次比较:2<36,则2和36要交换顺序,得到第三次排序: 25, 8,36, 2,9 第四次比较:2<9,要交换顺序,得到排序25, 8,36, 9, 2。经过 4 次比较后我们发现最小的一个数已经就位。这就是走过一趟排序,然后进行重复比较,直到最后的顺序正确。
5).动图演示:(图片转载网上博客)
6).代码:
java代码:
package 排序算法;
public class Maopao {
public static void main(String[] args) {
int [] a={3,8,25,6,16,98,25,64,12,0};//定义一个整型的数组
int t;
System.out.println("排序前的数组顺序");//输出提示语句
for(int i=0;i<a.length ;i++)//for循环遍历数组
System.out.print(a[i]+",");
System.out.println();//进行换行语句控制
for(int i=0;i<a.length-1;i++)//外层循环控制排序趟数
{
for(int j=0;j<a.length-1-i;j++)//内层循环控制每一趟排序多少次
{
if(a[j]<a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
System.out.println("排序后的数组顺序");
System.out.print("[");
for(int order:a )//用增强for来遍历数组,也可以用常规for循环
System.out.print(order+",");
System.out.println("]");
}
}
public static void main(String[] args) {
int [] a={3,8,25,6,16,98,25,64,12,0};//定义一个整型的数组
int t;
System.out.println("排序前的数组顺序");//输出提示语句
for(int i=0;i<a.length ;i++)//for循环遍历数组
System.out.print(a[i]+",");
System.out.println();//进行换行语句控制
for(int i=0;i<a.length-1;i++)//外层循环控制排序趟数
{
for(int j=0;j<a.length-1-i;j++)//内层循环控制每一趟排序多少次
{
if(a[j]<a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
System.out.println("排序后的数组顺序");
System.out.print("[");
for(int order:a )//用增强for来遍历数组,也可以用常规for循环
System.out.print(order+",");
System.out.println("]");
}
}
运行结果:
优化一:自己可以在控制台中输入任意大小的数组元素进行排序,不在是自定义的数组:
package 排序算法;
import java.util.Arrays;
import java.util.Scanner;
public class Maopao2 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入一个你想要排序的数组的大小:");
while(sc.hasNext())
{ //循环读入键入的数字存入数组中
int m=sc.nextInt();
//System.out.println(m);
int[] number=new int[m];
for(int i=0;i<m;i++)//循环读入一个数组的元素
{
number[i]=sc.nextInt();
}
// Arrays.sort(number);
System.out.println("你输入的数组是:");
System.out.println(Arrays.toString(number));
int t;
for(int i=0;i<number.length-1;i++)//外层循环控制排序趟数
{
for(int j=0;j<number.length-1-i;j++)//内层循环控制每一趟排序多少次
{
if(number[j]<number[j+1])
{
t=number[j];
number[j]=number[j+1];
number[j+1]=t;
}
}
}
System.out.println("冒泡排序后的数组顺序");
System.out.print("[");
for(int order:number)
System.out.print(order+",");
System.out.println("]");
}
}
}
运行结果如下:
javascript代码:将代码复制粘贴到webstorm创建的js文件中就可以直接运行。
function paixu() {
console.log("排序前的数组顺序:");
var a=[45,67,1,5,82];/* 定义一个数组*/
console.log(a);/*控制台输出数组*/
(function maopao() {
for(var i=0;i<a.length-1;i++){//外层循环控制排序趟数,有n个元素,就会有n-1趟比较
for(var j=0;j<a.length-1-i;j++){//内层循环控制每一趟排序多少次
if (a[j] < a[j + 1]) {
var tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
}
}
}
console.log("冒泡排序后的顺序是:")
console.log(a);
})();
}
paixu();/*函数自调用*/
运行结果:
2.选择排序
1).算法简介:表现最稳定的算法之一,选择排序(Selection-sort)是一种简单直观的排序算法,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。
2).基本思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
3).算法描述:
1、初始状态:无序区为a[1..n],有序区为空
2、第i趟排序(i=1,2,3...n-1)开始时,当前有序区和无序区分别为a[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 a[k],将它与无序区的第1个记录a交换,使a[1..i]aR[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区
3、n-1趟结束,数组有序化了
4).动图演示:(图片转载网上博客)
6).代码:
a.java代码
package 排序算法;
import java.util.Arrays;
import java.util.Scanner;
import sun.security.krb5.SCDynamicStoreConfig;
public class SelectionSort {
//选择排序法
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入你想排序的数组大小:");
while(sc.hasNext()){
int m=sc.nextInt();
int a[]=new int[m];
for(int x=0;x<m;x++){
a[x]=sc.nextInt();
}
System.out.println("你输入的数组是:");
System.out.println(Arrays.toString(a));
for(int i=0;i<a.length-1;i++){
int minindex=i;
int t;
for(int j=i+1;j<a.length;j++){
if(a[j]<a[minindex]){//循环寻找最小值
minindex=j; //保存最小值的索引
}
}
t=a[i];
a[i]=a[minindex];
a[minindex]=t;
}
System.out.println("选择排序后的数组顺序");
System.out.print("[");
for(int order:a)
System.out.print(+order+",");
System.out.print("]");
}
}
}
b. JavaScript的代码:
function SelectSort(a) {
var temp, maxindex;
var len = a.length;
console.time('选择排序耗时');
for (var i = 0; i < len - 1; i++) {//找到最大值的那个索引
maxindex = i;
for (var j = i+1; j <len; j++) {//从i后的无序找最大值,进行排序
if (a[j] > a[maxindex]) {
maxindex = j; //把最大值的索引给j
}
}
temp = a[i];
a[i] = a[maxindex];
a[maxindex] = temp;
}
console.timeEnd('选择排序耗时');
return a;
}
var a=[3,42,38,5,47,15,36,26,27,50,48,98,20];
console.log('你输入的数组顺序是:');
console.log(a);
console.log('选择排序的数组顺序:');
console.log(SelectSort(a));
运行结果:
你输入的数组顺序是:
[ 3, 42, 38, 5, 47, 15, 36, 26, 27, 50, 48, 98, 20 ]
选择排序的数组顺序:
选择排序耗时: 0.526ms
[ 98, 50, 48, 47, 42, 38, 36, 27, 26, 20, 15, 5, 3 ]
3.插入排序
1).算法简介:书上和好多博客上简单的解释就像和打扑克一样把牌插入,插入的方法就是按照某种方式把他放到合适的位置,
简单的排序中,就是把它放在两个数的中间,实现顺序的正确。
2).基本思想:它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
3).算法描述:
- 1>.从第一个元素开始,这个元素可以默认认为已经被排序;
- 2>.取出下一个元素,在已经排序的元素序列中从后向前扫描;
- 3>.如果该元素(已排序)大于新元素,将该元素移到下一位置;
- 4>.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
- 5>.将新元素插入到该位置后;
- 6>.重复步骤2~5。
4).动图演示:(图片转载网上博客)
5).代码:装载
java代码:
package com.test.insertsort;
/**
* 插入排序算法:
* 1、以数组的某一位作为分隔位,比如index=1,假设左面的都是有序的.
*
* 2、将index位的数据拿出来,放到临时变量里,这时index位置就空出来了.
*
* 3、从leftindex=index-1开始将左面的数据与当前index位的数据(即temp)进行比较,如果array[leftindex]>temp,
* 则将array[leftindex]后移一位,即array[leftindex+1]=array[leftindex],此时leftindex就空出来了.
*
* 4、再用index-2(即leftindex=leftindex-1)位的数据和temp比,重复步骤3,
* 直到找到<=temp的数据或者比到了最左面(说明temp最小),停止比较,将temp放在当前空的位置上.
*
* 5、index向后挪1,即index=index+1,temp=array[index],重复步骤2-4,直到index=array.length,排序结束,
* 此时数组中的数据即为从小到大的顺序.
*
* @author bjh
*
*/
public class InsertSort {
private int[] array;
private int length;
public InsertSort(int[] array){
this.array = array;
this.length = array.length;
}
public void display(){
for(int a: array){
System.out.print(a+" ");
}
System.out.println();
}
/**
* 插入排序方法
*/
public void doInsertSort(){
for(int index = 1; index<length; index++){//外层向右的index,即作为比较对象的数据的index
int temp = array[index];//用作比较的数据
int leftindex = index-1;
while(leftindex>=0 && array[leftindex]>temp){//当比到最左边或者遇到比temp小的数据时,结束循环
array[leftindex+1] = array[leftindex];
leftindex--;
}
array[leftindex+1] = temp;//把temp放到空位上
}
}
public static void main(String[] args){
int[] array = {38,65,97,76,13,27,49};
InsertSort is = new InsertSort(array);
System.out.println("排序前的数据为:");
is.display();
is.doInsertSort();
System.out.println("排序后的数据为:");
is.display();
}
}
JavaScript代码:
function insertsort() {
var a=[ 3, 42, 38, 5, 47, 15, 36, 26, 27, 50, 48, 98, 20 ];
console.log('当前数组元素:');
console.log(a);
var len=a.length; //定义数组的长度
var current,preindex; //定义两个索引
console.time('插入排序用时'); //计时器,用来计标记这个算法的所用时间
(function insert() {
for(var i=0;i<len;i++){ //遍历所有的数组元素,每次都拿出一个元素,进行插入比较
preindex=i-1;
current=a[i];
while(preindex>=0&& a[preindex]>current){ //插入时的比较,最后一个元素直到所有的元素结束
a[preindex+1]=a[preindex];
preindex--;
}
a[preindex+1] = current;
}
console.log('插入排序后的数组元素:');
console.log(a);
console.timeEnd('插入排序用时');
})();
}
insertsort();
运算结果:
当前数组元素:
[ 3, 42, 38, 5, 47, 15, 36, 26, 27, 50, 48, 98, 20 ]
插入排序后的数组元素:
[ 3, 5, 15, 20, 26, 27, 36, 38, 42, 47, 48, 50, 98 ]
插入排序用时: 0.619ms
4.希尔排序
1).算法简介:它是简单插入排序的更进一步改进,这种算法和插入排序算法不同之处就是首先比较距离比较远的元素。
2).基本思想:希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。先将整个待排序的记录分成若干个子序列,然后进行直接插入排序,待整个序列中的记录有了基本有序时,在对全体序列做一次插入排序。
3).算法描述:
1).先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组,将距离为d1的倍数的记录放在同一组中,在
各个组中进行插入排序
2).然后取第二个增量d2,(d2<d1),重复(1)分组和排序工作,
3).以此类推,直至所取的增量di=1(di<di-1<........d1),即所有的记录放在同一组中进行直接插入排序。
4).注意,一般d1=n/2;d(i+1)=di/2;如果结果是偶数,加1让他变成奇数来进行分组
4).举例说明:
一组记录[72,58,94,23,5]共有5个记录,进行希尔排序的演示:
1.先进行分组 d1=n/2=5/2=3 ,以3为距离进行分组: 就会有[72,23],[58,5][94]这三个基本组;
2.在各组中进行插入排序后,得到新的记录[23,5,94,72,58],
3.在进行第二次分组: d2=d1/2=1(取奇数),结果距离为1,所以分组结束,进行最后的直接插入排序
4.通过上述插入排序的方法得到最终的结果是[5,23,58,72,94]
5)代码演示:
java代码:
public static void shellSort(int[] a){
double gap = a.length;//增量长度
int dk,sentinel,k;
while(true){
gap = (int)Math.ceil(gap/2);//逐渐减小增量长度
dk = (int)gap;//确定增量长度
for(int i=0;i<dk;i++){
//用增量将序列分割,分别进行直接插入排序。随着增量变小为1,最后整体进行直接插入排序
for(int j=i+dk;j<a.length;j = j+dk){
k = j-dk;
sentinel = a[j];
while(k>=0 && sentinel<a[k]){
a[k+dk] = a[k];
k = k-dk;
}
a[k+dk] = sentinel;
}
}
//当dk为1的时候,整体进行直接插入排序
if(dk==1){
break;
}
}
}
JavaScript代码:
//希尔排序算法:
/*
* 1.进行对所有的记录的分组
* 2.对分组的记录进行直接插入排序
* 3.直到所有的分组结束,即di=1,对最后的记录进行直接的插入排序
* */
function shellsort(arr) {
var len = arr.length;
var gap=1;
var temp;
console.log('你定义的的数组是:');
console.log(arr);
console.time('希尔排序时间');
while (gap < len / 2) { //动态定义分组间隔
gap = gap * 2 + 1;
}
for (gap; gap > 0; gap = Math.floor(gap/2))
{//排序的趟数,对所有的记录进行分组,直到分组的距离为1为止
for (var i = gap; i < len; i++)
{ //对分组类中的记录进行插入排序
temp = arr[i];
for (var j = i - gap; j >= 0 && arr[j] > temp; j -= gap) {
arr[j + gap] = arr[j];
}
arr[j + gap] = temp;
}
}
console.timeEnd('希尔排序时间');
console.log('希尔排序的数组')
return arr;
}
var arr=[3,44,38,5,47,15,36,26,27,2,46,4,19,50,48];
console.log(shellsort(arr));
运行结果:
你定义的的数组是:
[ 3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48 ]
希尔排序时间: 0.592ms
希尔排序的数组
[ 2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50 ]
5.归并排序
1).算法简介:和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(n log n)的时间复杂度。代价是需要额外的内存空间。。
2).基本思想:归并排序是建立在归并操作上的一种有效的排序算法,归并排序是将两个或两个以上的有序子表合并成一个新的有序表,初始化时,把含有n个记录的带排序的序列看做是n个长度都为1的有序子表组成,将他们两两归并,得到长度为2的若干有序表,再对他们合并,直到得到最后的正确排序。
3).算法描述:
1.先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组,将距离为d1的倍数的记录放在同一组中,在
各个组中进行插入排序
2.然后取第二个增量d2,(d2<d1),重复(1)分组和排序工作,
3.以此类推,直至所取的增量di=1(di<di-1<........d1),即所有的记录放在同一组中进行直接插入排序。
4.注意,一般d1=n/2;d(i+1)=di/2;如果结果是偶数,加1让他变成奇数来进行分组