冒泡排序
算法思想:
若数据个数为n,一次循环n-1次,每次比较相邻两个数据,以升序排列为例,若前者比后者
大,则交换两数据,即可得依次循环排序后的最大值放在最后面,之后循环n-2次…依次类推直
至排序完成。
代码:
1 |
|
算法复杂度:$T(n)=O(n^2)$
优点:对于链表等结构有特有的优势
插入排序
算法思想:
若数据个数为n,以升序为例,则可认为第一个数据已经排序,只有循环比较之后的数据即可。暂存当次数据,是指与之前排序的结果(有序对)比较,在有序对中找到相应的插入位置,直至
结束
代码:
1 | Status InsertSort(SqList &L){ |
算法复杂度:T(n)=O(n+I) I为逆序对个数
小结:每次交换的次数为逆序对个数
同时,若I的个数较小,则可发现插入排序较好
但是冒泡排序对于链表、数组等这种连续排列有其优势,而插入则没有
缺点:每次只消除一个逆序对
希尔排序
算法思想:
将序列分成若干子序列分别进行直接插入排序,比如五间隔、三间隔等等直至进行一间隔排序
定义增量序列:DM>DM-1>…>D1=1对每个Dk进行“Dk-间隔”排序(k=N,M-1,,…1)
Dk间隔排序后仍然保持Dk-1序列有序
原始希尔排序:
DM=floor(N/2),Dk=floor(Dk+1/2)
代码:
1 | Status ShellSort(SqList &L){ |
选择排序
算法思想:
每次从i到length中找出最小值放在前面的有序序列中。
代码:
1 | Status SelectionSort(SqList &L){ |
快速排序
算法思想:
一次快排:每次high从高位向前找到第一个比枢纽记录小的记录,交换low和high两记录,之后low从低位向高位找到第一个比枢纽记录大的记录,交换low和high两记录,直至最后high与low相等为止,完成一次快排,所得结果,枢纽左边的数都比它小,枢纽右边的数都比它大。
采用递归,对枢纽两边的序列二分,分两部分再次进行一次快排,以此类推,直至low与high相等
代码:
1 | int Partition(SqList &L,int low,int high) { |
堆排序
算法思想:
实质是对选择排序的改进。
堆的定义:n个元素的序列{k1,k2,…,kn}当且仅当满足下关系时,称之为堆
{ki<=k2i,ki<=k2i+1; 或 {ki>=k2i,ki>=k2i+1;
算法采用大顶堆排序,无序序列建堆就是一个反复筛选的过程。
一次筛选:将所有记录排列成完全二叉树形式,一次筛选从最后一个非终端节点(第floor(n/2))开始,每次将当前结点的子树中最大记录与当前根结点交换,当前结点依次递减至根结点为止,交换根结点与最后一个结点的值。
代码:
1 | typedef SqList HeapType; |
归并排序
递归算法
基本思路
数组排序任务可以如下完成:
①把前一半排序
②把后一半排序
③把两半归并到一个新的有序数组,然后再拷贝回原数组,排序完成。
时间复杂度
时间复杂度:
T(n) = 2 * T(n / 2) + an
= 2 * (2 * T(n / 4) + an / 2) + an
= 4 * T(n / 4) + 2 * an
= 4 * (2 * T(n / 8) + an / 4) + 2 * an
= 8 * T(n / 8) + 3 * an
…
= 2 ^ kt(n / 2 ^ k) + kan
一直做到 n/2^k=1(此时k=log2(n)),
T(n) = 2^k * T(1) + k * a * n
=2^k * T(1) + k * a * n
=2^k + k * a * n
=n + a * n * log2(n)
复杂度$O(nlog n)$
1 | /* |
非递归算法
基本思路
k=2
先22归并
再44归并
…
注意剩余不足整数倍的剩余元素排序
代码
1 |
|