概述
插入排序
直接插入排序
-
基本思想:采用顺序查找法的插入排序 -
算法实现 #include<stdio.h>
#include"SqListForSort.h"
void InsertSort(SqList *L) {
int i, j;
for(i = 2; i <= L->length; i++)
if(L->elem[i] < L->elem[i-1]) {
L->elem[0] = L->elem[i];
for(j = i-1; L->elem[0] < L->elem[j]; j--)
L->elem[j+1] = L->elem[j];
L->elem[j+1] = L->elem[0];
}
}
int main() {
KeyType array[] = {10, 3, 5, 16, 7, 32, 83, 23, 7, 54, 29, 96};
SqList L = CreateList(array, 11);
ShowList(L);
InsertSort(&L);
ShowList(L);
return 0;
}
-
算法分析
二分插入排序
-
基本思想:采用二分查找法的插入排序 -
算法实现 #include<stdio.h>
#include"SqListForSort.h"
void BInsertSort(SqList *L) {
int i, j, low, high, mid;
for(i = 2; i <= L->length; i++)
if(L->elem[i] < L->elem[i-1]) {
L->elem[0] = L->elem[i];
low = 1, high = i-1;
while(low <= high) {
mid = (low+high)/2;
if(L->elem[0] < L->elem[mid])
high = mid - 1;
else low = mid + 1;
}
for(j = i; j-1 >= high+1; j--)
L->elem[j] = L->elem[j-1];
L->elem[high+1] = L->elem[0];
}
}
int main() {
KeyType array[] = {10, 3, 5, 16, 7, 32, 83, 23, 7, 54, 29, 96};
SqList L = CreateList(array, 11);
ShowList(L);
BInsertSort(&L);
ShowList(L);
return 0;
}
-
算法分析
- 时间性能
- 二分插入排序减少了比较次数,但没有减少移动次数
- 平均性能优于直接插入排序
- 时间复杂度
O
(
n
2
)
O(n^2)
O(n2)
- 空间性能:空间复杂度
O
(
1
)
O(1)
O(1)
- 稳定性:稳定
- 不适合在链式存储结构上实现
希尔排序
-
基本思想 利用了直接插入排序在个数较少、基本有序的情况下效率更高的特点 先将整个待排记录序列分割成若干子序列,分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
- 一次移动,移动位置较大,跳跃式地接近排序后的最终位置,最后一次只需要少量移动
- 增量序列必须是递减的,最后一个必须是1;增量序列应该是互质的
-
算法实现 #include<stdio.h>
#include"SqListForSort.h"
void ShellInsert(SqList *L, int dk) {
int n, i, j;
for(n = 1; n <= dk; n++)
for(i = n; i <= L->length; i = i+dk)
if(L->elem[i] < L->elem[i-dk]) {
L->elem[0] = L->elem[i];
for(j = i-dk; L->elem[0] < L->elem[j] && j >= n; j = j-dk)
L->elem[j+dk] = L->elem[j];
L->elem[j+dk] = L->elem[0];
}
}
void ShellSort(SqList *L, int dlta[], int t) {
for(int k = 0; k <= t-1; k++)
ShellInsert(L, dlta[k]);
}
int main() {
KeyType array[] = {10, 3, 5, 16, 7, 32, 83, 23, 7, 54, 29, 96};
int dlta[] = {5, 3, 1};
SqList L = CreateList(array, 11);
ShowList(L);
ShellSort(&L, dlta, 3);
ShowList(L);
return 0;
}
-
算法分析
- 时间性能:时间复杂度是n和d的函数,根据经验介于
O
(
n
1.25
)
O(n^{1.25})
O(n1.25)~
O
(
1.6
n
1.25
)
O(1.6n^{1.25})
O(1.6n1.25)之间
- 空间性能:空间复杂度
O
(
1
)
O(1)
O(1)
- 稳定性:稳定
- 不适合在链式存储结构上实现
交换排序
- 基本思想:两两比较,如果发逆序则交换,直到所有记录都排好序为止
冒泡排序
-
基本思想:按顺序两两比较,逆序则交换 -
算法实现 #include<stdio.h>
#include"SqListForSort.h"
void BubbleSort(SqList *L) {
int i, j, flag;
for(i = L->length, flag = 0; i >= 2; i--) {
if(flag) return;
for(j = 1, flag = 1; j+1 <= i; j++)
if(L->elem[j] > L->elem[j+1]) {
flag = 0;
L->elem[0] = L->elem[j];
L->elem[j] = L->elem[j+1];
L->elem[j+1] = L->elem[0];
}
}
}
int main() {
KeyType array[] = {10, 3, 5, 16, 7, 32, 83, 23, 7, 54, 29, 96};
SqList L = CreateList(array, 11);
ShowList(L);
BubbleSort(&L);
ShowList(L);
return 0;
}
-
算法分析
快速排序
-
基本思想 任取一个元素为中心,所有比它小的元素一律前放,比它大的元素一律后放,形成左右两个子表;对各子表重新选择中心元素并依此规则调整(递归思想),直到每个子表的元素只剩一个 -
算法实现 #include<stdio.h>
#include"SqListForSort.h"
int Partition(SqList *L, int low, int high) {
L->elem[0] = L->elem[low];
while(low < high) {
for(; low < high; high--)
if(L->elem[high] < L->elem[0]) {
L->elem[low] = L->elem[high];
break;
}
for(; low < high; low++)
if(L->elem[low] >= L->elem[0]) {
L->elem[high] = L->elem[low];
break;
}
}
L->elem[low] = L->elem[0];
return low;
}
void Qsort(SqList *L, int low, int high) {
int privotloc;
if(low < high) {
privotloc = Partition(L, low, high);
Qsort(L, low, privotloc-1);
Qsort(L, privotloc+1, high);
}
}
void QuickSort(SqList *L) {
Qsort(L, 1, L->length);
}
int main() {
KeyType array[] = {10, 3, 5, 16, 7, 32, 83, 23, 7, 54, 29, 96};
SqList L = CreateList(array, 11);
ShowList(L);
QuickSort(&L);
ShowList(L);
return 0;
}
-
算法分析
选择排序
简单选择排序
-
基本思想:在待排序的数据中选出最大(小)的元素放在其最终的位置 -
算法实现 #include<stdio.h>
#include"SqListForSort.h"
void SelectSort(SqList *L) {
int i, j, minloc;
for(i = 1; i <= L->length-1; i++) {
for(j = i, minloc = i; j <= L->length; j++)
if(L->elem[j] < L->elem[minloc])
minloc = j;
L->elem[0] = L->elem[i];
L->elem[i] = L->elem[minloc];
L->elem[minloc] = L->elem[0];
}
}
int main() {
KeyType array[] = {10, 3, 5, 16, 7, 32, 83, 23, 7, 54, 29, 96};
SqList L = CreateList(array, 11);
ShowList(L);
SelectSort(&L);
ShowList(L);
return 0;
}
-
算法分析
- 时间性能
- 最好情况(正序)移动次数为0,最坏情况(逆序)移动次数为3(n-1)
- 不管序列如何,比较次数都一样,都为
∑
i
=
1
n
?
1
(
n
?
i
)
=
n
2
(
n
?
1
)
\sum_{i = 1}^{n-1}{(n-i)} = \frac{n}{2}(n-1)
∑i=1n?1?(n?i)=2n?(n?1)
- 时间复杂度
O
(
n
2
)
O(n^2)
O(n2)
- 空间性能:空间复杂度
O
(
1
)
O(1)
O(1)
- 稳定性:不稳定
堆排序
-
基本思想
-
堆的定义 若n个元素的序列满足
{
a
1
,
a
2
,
.
.
.
,
a
n
}
\{a_1, a_2, ..., a_n\}
{a1?,a2?,...,an?}满足:
{
a
i
≤
a
2
i
a
i
≤
a
2
i
+
1
或
{
a
i
≥
a
2
i
a
i
≥
a
2
i
+
1
\begin{cases} a_i \le a_{2i} \\ a_i \le a_{2i+1} \end{cases} 或 \begin{cases} a_i \ge a_{2i} \\ a_i \ge a_{2i+1} \end{cases}
{ai?≤a2i?ai?≤a2i+1??或{ai?≥a2i?ai?≥a2i+1?? ? 则分别称该序列
{
a
1
,
a
2
,
.
.
.
,
a
n
}
\{a_1, a_2, ..., a_n\}
{a1?,a2?,...,an?}为小根堆和大根堆 ? 从堆的定义可以看出,堆实质是满足如下性质的完全二叉树:二叉树中任一非叶子结点均小于/大于它的孩子结点
-
算法实现 -
算法分析
- 时间性能:时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
- 空间性能:时间复杂度
O
(
n
)
O(n)
O(n)
- 稳定性:不稳定
归并排序
-
基本思想:将两个或两个以上的有序子序列归并为一个有序序列 -
算法实现 #include<stdio.h>
#include"SqListForSort.h"
int min(int a, int b) {
return a < b ? a : b;
}
void Merge(SqList *L, SqList *MergeL, int low, int mid, int high) {
int i, j, k;
i = low, j = mid + 1, k = low;
while(i <= mid && j <= high)
MergeL->elem[k++] = (L->elem[i] <= L->elem[j])? L->elem[i++]: L->elem[j++];
while(i <= mid)
MergeL->elem[k++] = L->elem[i++];
while(j <= high)
MergeL->elem[k++] = L->elem[j++];
}
void MergeSort(SqList *L) {
int low, mid, high, range;
SqList mergeL, *MergeL, *t;
MergeL = &mergeL;
MergeL->length = L->length;
for(range = 1; range <= L->length; range *= 2) {
for(low = 1; low <= L->length; low += range*2) {
high = min(low + range*2 - 1, L->length);
mid = min(low + range - 1, L->length);
Merge(L, MergeL, low, mid, high);
}
t = L, L = MergeL, MergeL = t;
}
}
int main() {
KeyType array[] = {10, 3, 5, 16, 7, 32, 83, 23, 7, 54, 29, 96};
SqList L = CreateList(array, 11);
ShowList(L);
MergeSort(&L);
ShowList(L);
return 0;
}
-
算法分析
基数排序
各种排序方法的比较
- 算法设计
- 简单排序(直接插入排序、二分插入排序、冒泡排序、简单选择排序)都是顺序遍历元素,二分排序在查找时是递归的
- 快速排序、堆排序、归并排序是递归的,采用了分治法
- 时间性能
- 根据时间复杂度分类
-
O
(
n
)
O(n)
O(n):基数排序;最快,但不是所有都能用
-
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn):快速排序、堆排序、归并排序;其中快速排序最优
- 约
O
(
n
1.3
)
O(n^{1.3})
O(n1.3):希尔排序
-
O
(
n
2
)
O(n^2)
O(n2):简单排序(直接插入排序、二分插入排序、冒泡排序、简单选择排序);二分插入排序最优
- 正序情况下
- 直接插入排序、二分插入排序和冒泡排序能达到
O
(
n
)
O(n)
O(n),快速排序退化为
O
(
n
2
)
O(n^2)
O(n2)
- 其他排序时间复杂度保持不变
- 正序情况下,直接插入排序是最快的
- 空间性能
-
O
(
1
)
O(1)
O(1):简单排序(直接插入排序、二分插入排序、冒泡排序、简单选择排序)、希尔排序、堆排序
-
O
(
l
o
g
n
)
O(logn)
O(logn):快速排序
-
O
(
n
)
O(n)
O(n):归并排序、基数排序
- 稳定性
- 简单选择排序、希尔排序、快速排序、堆排序是不稳定的,其他都是稳定的
|