前言
由于考研的原因需要复习算法课程,故在此记录下复习笔记,希望能够帮到初学算法的同学们
本笔记是基于慕课网的算法课程编写的,仅做个人记录所用
本笔记不仅仅记录各种算法的写法,还会探究每种算法的内涵,希望大家看完后都能有所收获
由于记笔记的时间较为紧张,故有些地方会略写,还望遇到我略写之处大家可以自行扩展
笔记统一使用C++语言在VS2015上编写
若有所缺漏还烦请指正!
本章简介
本章主要围绕两个最基础的O(n^2)的算法:选择排序和插入排序展开
其中还包含了些许功能型函数的书写
研究后发现其实就算是O(n^2)级别的算法有自己独特的用处!
选择排序 Selection Sort
1.找出最小的数字所在的位置
2.将最小的数字与最前方的位置里的数字交换
3.再在除了最小之外的其他数字中寻找最小的数字
4.将其与第二个位置上的数字交换
5.以此类推直到结束
main函数如下:
选择排序函数使用模板(泛型)后修改如下:
观察发现,选择排序在任何情况下都要将两层循环执行完成,所以非常的慢
测试用例
新建SortTestHelper.h
在SortTestHelper.h中编写函数generateRandomArray
n个元素的随机数组,范围在[rangL,rangR],返回指向第一个元素的指针
在SortTestHelper.h中编写函数:printArray
在SortTestHelper.h中编写测试:testSort
其中assert的位置要在两个colck计时之外,并且要在cout输出语句之前.才能保证既不影响计时的准确性,又能在出错时计时中止程序.
在SortTestHelper.h中编写断言:isSorted
插入排序 Insertion Sort
1.像打扑克牌时整理排序一样
2.第一个数不动
3.第二个数跟第一个比大小,若不对则交换
4.第三个数和第二个数比,若不对则交换后跟第一个数比
5.以此类推直到结束
排序函数:
main函数:
在SortTestHelper.h中添加复制数组函数:copyIntArray
其中C4996报错的解决方法如下:
对比结果如图:
插入排序时间比选择排序还要多?
因为交换操作比比较操作更费时!
插入排序改进
思路是尽量减少交换操作,故可以变成"事先储存+多次对比+一次赋值"的形式
其中第N个元素的交换思路如下:
1.将第N个元素保存一份副本
2.与第N-1个元素比较,若比N-1小则将N-1复制到N
3.与N-2比较,类推
4.与N-i-1比较,发现N-i-1元素比N小,则将保存的副本赋值给N-i即可
其中插入排序代码修改为:
将swap()的三次操作变成了赋值的一次操作
并且插入排序比起选择排序有了提前终止的功能
故再次执行后对比结果如下:
插入排序的精髓在于提前终止,为了验证这一点我们创造一个近乎有序的数组,再观察两种排序的时间,创造近乎有序的数组的思路是:
先创造一个顺序数组,再给定次数的随机调换顺序数组中的元素即可
根据这个思路,generateNearlyOrderedArray函数如下:
在main函数中调用generateNearlyOrderedArray并赋值50进行测试,发现插入与选择的差距的确变大了很多:
总结说来,插入排序对近乎有序的数组进行排序的性能非常高
这使得其在实践中应用非常广泛,因为我们要排序的数组大多都是近乎有序的
若数组有序,则插入排序会变成O(n)级别的算法!即每个对比一次即可
扩展
希尔排序 Shell Sort是插入排序的延伸算法,具有O(nlogn)的时间复杂度
插入排序与希尔排序差别如下:
插入排序是与前一个元素比较
希尔排序是与前h个元素比较,随着h缩小到1,可以将无序数组变成近乎有序的数组,再变成有序数组,大大提升排序效率
思考
1.使用同样的方法分析优化冒泡排序 Bubble Sort
2.实现希尔排序的过程