三种常见的排序算法  

          近期因实际需求需要使用到排序算法,就此将常见的三种排序算法进行复习、整理并记录,用于以后的参考,在程杰老师的《大话数据结构》一书中生动的阐述了多种排序算法(冒泡排序、选择排序、堆排序、快速排序、希尔排序、归并排序),本文借鉴《大话数据结构》一书中的概念并结合自身的理解记录其中三种排序算法的原理、实现及时间复杂度的简单分析。

       在进行实际的算法记录前先回顾一下一个概念:时间复杂度。

时间复杂度是用来描述一个算法的运行时间的量,通常情况,解决一个问题,使用的时间最少的算法,其时间复杂度要低于使用时间多的算法。下面看一下算法时间复杂度的定义:

在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n)=O(f(n))。它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称时间复杂度,其中f(n)是问题规模n的某个函数[1]

对于使用大写O()来表示算法复杂度的记法称为大O记法。推导大O阶方法:

1、用常数1取代运行时间中的所有加法常数。

2、只保留最高阶项。

3、将最高阶项系数更改为1。

例如计算一个问题的结果的执行次数为T(n) =(1+n) * n/2(n) =(1+n) * n/2;时间复杂度的推导:

变换得:  ,按照上面的步骤可得到其时间复杂度为:O()

常见的时间复杂度有:常数阶:  线性阶:平方阶: 对数阶: 立方阶: 指数阶:

 各时间复杂度的耗时从小到为:

   >   >  >  > 

 

问题模型:当前在有很多个的公司参与某个暖通空调项目的竞标,需要统计这些公司的规模(通过员工人

数进行评判,人数越多规模越大),已经拿到了所有参与竞标的公司数据(包括人数),现在需要最快的获

取所有参竞标公司的一个规模情况。

       解决这个问题其实就是需要将参与竞标公司按照公司的现有的员工人数排序,就可以得到每个公司在参与竞标公司中的规模如何了,下面我们来看看使用四种不同的排序算法如何实现。

 

  • 冒泡排序法

冒泡排序法是最简单、最容易理解、最好实现的一种排序算法,但其时间复杂度也比较高;冒泡法是如何实现牌排序的呢?

如图1.1[2]所示,对一个组数{5,4,6,7,8}进行由大到小的排序,通过比较换位的方式,由数组中最后一个数(记为MAX)依次与前面数进行比较,如果前面的数小于MAX,则与之换位,否则将前面的数赋值给MAX,然后继续向前比较,在比较n – 1(n为该数组的实际元素个数或长度)次后便可将该数组最大的数据排在数组首位;在第一轮结束后开始第二轮比较,还是从最后一个数开始,重复第一轮的步骤,只不过,不与当前数组的第一个数进行比较,因为可以确定第一个数为该数组最大值了。第二轮比较的次数为:n-2,第三轮比较的次数为n – 3。故而参数比较的次数f(n) = (n –1) + (n-2) + (n-3 )+ + + …+1,其时间复杂度为:O(n2),下面看一下使用冒泡算法解决公司规模问题。

                                                                     

 

                                                                                        图1.1[2]

1、建立公司模型

public class Company {
	private String name;// 公司名称
	private int employeesNum; // 公司员工数
	public String getName() {return name;}
	public void setName(String name) {this.name = name;}
	public int getEmployeesNum() {return employeesNum;}
	public void setEmployeesNum(int employeesNum) {this.employeesNum = employeesNum;
    }
}

2、算法实现

    /**
	 * <冒泡排序法实现排序>
	 * @param recordList
	 */
	private static void bubbleSort(List<Company> recordList){
		int len = recordList.size();
		long timeBegin = System.currentTimeMillis();
		for (int i = 0; i < len - 1; i ++) {
			for (int j = i + 1; j <= len - 1; j ++) {
				Company cpi = recordList.get(i);
				Company cpj = recordList.get(j);
				if (cpi.getEmployeesNum() > cpj.getEmployeesNum()) {
					recordList.set(i, cpj);
					recordList.set(j, cpi);
				}
			}
		}
	}

 

  • 选择排序法

       与冒泡排序非常类似,不同之处在于选择排序算法通过记录每一轮比较的最大或最小值,在每一轮比较结实结束后才开始交换数组中的元素位置,而冒泡排序是只要满足比较的要求就调整元素顺序。选择排序的的时间复杂度也为O(n2),但在整体性能上要优于冒泡排序。

    /**
	 * <选择排序算法实现排序>
	 * @param recordList
	 */
	private void selectSort(List<Company> recordList){
		for (int i = 0; i < recordList.size() - 1; i ++) {
			Company temp = recordList.get(i);
			int min = i;
			for (int j = i + 1; j < recordList.size(); j ++) {
            if (temp.getEmployeesNum() > recordList.get(j).getEmployeesNum()) {
					temp = recordList.get(j);
				    min = j;
                    }
			    }
			if (min != i) {
				recordList.set(min, recordList.get(i));
				recordList.set(i, temp);
			}
		}
	}

 

  • 快速排序法

       快速排序法选取一个基数(通常选取为记录的第一个),通过一趟排序将元素分割成独立的两部分,这两部分分别比基数大和比基数小的两部分,然后再对两部分的记录实施相同的分割操作,直到分割后得到的元素为一个为止停止分割,便完成了排序。

                                                      

 

                                                                                             图2.1

 

        如图2.1所示,将数组{5、4、9、3、7}分割为两部分的示意图,选取第一个元素为基数,存入temp中,然后使用temp从最后一个原素开始比较,第五个元素7>5不改变元素位置(i=1,j=5),第四个元素3<temp,将第四个元素的值赋给第一个元素的位置(i=1,j=4);从第一个位置开始与temp比较,第一个位置刚被赋值为小于temp的值,不变,第二个元素4<temp,位置不变(1=2,j=4),第三个元素9>temp将第四个元素赋值为第三个元素的值(i=3,j=4),将第三个元素赋值为temp。得到的数组为{3、4、5、9、7},将小于5和小于5的元素分割在了5的两边。

                                                                      

                                                                                                图2.2

      图2.2所示,分别对两个字数组进行相同的操作,得到了有序数组{3、4、5、7、9}。在最有好的情况下,快速排序算法的时间复杂度为O(nlogn),在最差的情况时间复杂度为:O(n2),这主要取决于我们选取的基数,所取的基数越是接近这个数列的中间数,计算的次数越少。

   /**
	 * @desc <快速排列算法实现>
	 * @author wukun4
	 * @param commonDownRecordList
	 */
     private static void quickSort(List<Company> recordList, int begin, int end){
		int i = begin;
		int j = end - 1;
		Company temp = recordList.get(begin);
		while (i < j) {
        while (i < j && recordList.get(j).getEmployeesNum() > temp.getEmployeesNum()) {
				j --;
			}
			recordList.set(i, recordList.get(j));
        while (i < j && recordList.get(i).getEmployeesNum() <= temp.getEmployeesNum()) {
				i ++;
			}
			recordList.set(j, recordList.get(i));
		}
		recordList.set(i, temp);
		quickSort(recordList, begin, i - 1);
		quickSort(recordList, i + 1, end);
	}

参考文献:

【1】《大话数据结构》程杰 –北京:清华大学出版社2011.6

【2】https://blog.csdn.net/zcl_love_wx/article/details/83576962

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值