在线编程——排序算法总结

在线编程——排序算法总结

      找实习,阿里一面遇到手写快排,写出来感觉没错(VS2013能通过),但在阿里的测试平台上运行未通过。细思极恐,赶紧总结一波。有幸看到SteveWang的两篇博客:排序算法总结(1)排序算法总结(2),总结的相当详细,我这里算是重新拜读一遍,结合自己的理解写下来。

一、排序算法分类,稳定性分析,时间复杂度与空间复杂度总结表

       我们通常所说的排序算法往往指的是内部排序算法,即数据记录在内存中进行排序。而外部排序是指大文件的排序,即待排序的记录存储在外存储器上,在排序过程中需要进行多次的内、外存之间的交换。

      (一)内部排序算法大体可分为两大类:

        1、比较排序,时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序选择排序插入排序归并排序堆排序快速排序等。

然而,参考博客:https://blog.csdn.net/zlele0326/article/details/51281578,比较排序算法可以继续分为下面几类:

(1)插入排序:直接插入排序,二分法插入排序,希尔排序;

(2)选择排序:简单选择排序,堆排序;

(3)交换排序:冒泡排序,快速排序;

(4)归并排序;

(5)基数排序;

  2、非比较排序,时间复杂度可以达到O(n),主要有:计数排序基数排序桶排序等。

(二)稳定性分析

        排序算法稳定性的简单形式化定义为:如果Ai = Aj,排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排序算法是稳定的。通俗地讲就是保证排序前后两个相等的数的相对顺序不变。

  对于不稳定的排序算法,只要举出一个实例,即可说明它的不稳定性;而对于稳定的排序算法,必须对算法进行分析从而得到稳定的特性。需要注意的是,排序算法是否为稳定的是由具体算法决定的,不稳定的算法在某种条件下可以变为稳定的算法,而稳定的算法在某种条件下也可以变为不稳定的算法。

  例如,对于冒泡排序,原本是稳定的排序算法,如果将记录交换的条件改成A[i] >= A[i + 1],则两个相等的记录就会交换位置,从而变成不稳定的排序算法。

  其次,说一下排序算法稳定性的好处。排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,前一个键排序的结果可以为后一个键排序所用。基数排序就是这样,先按低位排序,逐次按高位排序,低位排序后元素的顺序在高位也相同时是不会改变的。

(三)排序算法总结表

      尽管记了很多次几个排序算法的时间复杂度与空间复杂度表格,日子长了又忘了,心累,各种排序的稳定性,时间复杂度、空间复杂度、稳定性总结如下图(参考:https://blog.csdn.net/foreverling/article/details/43798223):


图1


图2

        网上现主要有两个版本的排序表格,如上图1,图2所示。可以看到两张图中希尔排序的时间复杂度不同,以及快速排序的空间复杂度不同,那究竟是什么?

(1)希尔排序时间复杂度分析:(摘自百度百科),希尔排序算法是直接插入排序算法的一种改进,减少了其复制的次数,速度要快很多。希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n^2),而Hibbard增量的希尔排序时间复杂度为O(n^3/2),希尔排序时间复杂度的下界是n*log2n。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择,但是比O( n^2 )复杂度的算法快得多。并且希尔排序非常容易实现,算法代码短而简单。此外,希尔算法在最坏的情况下和平均情况下执行效率相差不是很多,与此同时快速排序在最坏的情况下执行的效率会非常差。专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若在实际使用中证明它不够快,再改成快速排序这样更高级的排序算法. 希尔排序算法的性能与所选取的分组长度序列有很大关系。只对特定的待排序记录序列,可以准确地估算关键词的比较次数和对象移动次数。想要弄清关键词比较次数和记录移动次数与增量选择之间的关系,并给出完整的数学分析,至今仍然是数学难题。

(2)快速排序空间复杂度分析:详见博客(https://blog.csdn.net/yuzhihui_no1/article/details/44198701),首先就地快速排序使用的空间是O(1)的,也就是个常数级;而真正消耗空间的就是递归调用了,因为每次递归就要保持一些数据,即快速排序的空间复杂度为:O(logn) ~O( n ) 。

最优的情况下空间复杂度为:O(logn)  ;每一次都平分数组的情况

最差的情况下空间复杂度为:O( n )      ;退化为冒泡排序的情况


二、比较排序

1、直接插入排序

插入排序是一种简单直观的排序算法。它的工作原理非常类似于我们抓扑克牌


        对于未排序数据(右手抓到的牌),在已排序序列(左手已经排好序的手牌)中从后向前扫描,找到相应位置并插入。

  插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

  具体算法描述如下:

       (1) 从第一个元素开始,该元素可以认为已经被排序;

       (2) 取出下一个元素,在已经排序的元素序列中从后向前扫描;

       (3) 如果该元素(已排序)大于新元素,将该元素移到下一位置;

       (4) 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;

       (5) 将新元素插入到该位置后;

       (6) 重复步骤2~5;

C++代码为:

#include <iostream>
#include <vector>
using namespace std;

// 分类 ------------- 内部比较排序
// 数据结构 ---------- 向量
// 最差时间复杂度 ---- 最坏情况为输入序列是降序排列的,此时时间复杂度O(n^2)
// 最优时间复杂度 ---- 最好情况为输入序列是升序排列的,此时时间复杂度O(n)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定

vector<int> InsertionSort(vector<int> A)
{
	for (int i = 1; i < A.size(); i++)         // 类似抓扑克牌排序
	{
		int get = A[i];                 // 右手抓到一张扑克牌
		int j = i - 1;                  // 拿在左手上的牌总是排序好的
		while (j >= 0 && A[j] > get)    // 将抓到的牌与手牌从右向左进行比较
		{
			A[j + 1] = A[j];            // 如果该手牌比抓到的牌大,就将其右移
			j--;
		}
		A[j + 1] = get; // 直到该手牌比抓到的牌小(或二者相等),将抓到的牌插入到该手牌右边(相等元素的相对次序未变,所以插入排序是稳定的)
	}
	return A;
}

int main()
{
	//输入不定长的待排序列
	vector<int> vec;
	int temp;
	char t;
	cout << "输入待排序列为:";
	do{
		cin >> temp;
		vec.push_back(temp);
	} while ((t=cin.get())!='\n');
	/////////////////////////////////////////////////////////////////////////////////////
	int n = vec.size();//待排序列的长度 ,若输入为数组A,则int n = sizeof(A) / sizeof(int);
	cout << "排序前的结果为:";
	for (int i = 0; i < n; i++)
	{
		cout << vec[i] << " ";
	}
	cout << endl;
	/////////////////////////////////////////////////////////////////////////////////////
	vector<int> res = InsertionSort(vec); //调用直接插入排序算法
	cout << "排序后的结果为:";
	for (int i = 0; i < n; i++)
	{
		cout << res[i] << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}

动态图来自:http://www.cnblogs.com/eniac12/p/5329396.html#3972917


        插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,比如量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,用于少量元素的排序(通常为8个或以下)。


猜你喜欢

转载自blog.csdn.net/zichen_ziqi/article/details/80419920