直接插入排序
算法原理
- 从
A
[
2
]
A[2]
A[2]开始,到
A
[
n
]
A[n]
A[n],查找出
A
[
i
]
A[i]
A[i]在
A
[
1
…
i
−
1
]
A[1…i-1]
A[1…i−1]中的插入位置
k
k
k
- 将
A
[
k
…
i
−
1
]
A[k…i-1]
A[k…i−1]中所有元素位置依次后移一个位置
- 将
A
[
i
]
A[i]
A[i]复制到
A
[
k
]
A[k]
A[k]
代码实现
void InsertSort(int A[], int n){
int i, j;
for(i=2; i<=n; i++){
if(A[i]<A[i-1]){
A[0] = A[i];
for(j=i-1; A[0]<A[j]; j--)
A[j+1] = A[j];
A[j+1] = A[0];
}
}
}
举例
性能分析
- 空间复杂度:只使用了常数个辅助单元,空间复杂度为
O
(
1
)
O(1)
O(1)
- 时间复杂度
- 最好情况:元素已经有序,只需比较,不移动元素,时间复杂度为
O
(
n
)
O(n)
O(n)
- 最坏情况:逆序,比较次数达到最大,为
∑
i
=
2
n
i
\sum^n_{i=2}i
∑i=2ni,移动次数也达到最大,为
∑
i
=
2
n
(
i
+
1
)
\sum^n_{i=2}(i+1)
∑i=2n(i+1)
- 平均情况:时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)
- 稳定性:稳定
折半插入排序
算法原理
- 直接插入排序中,总是边比较边移动元素
- 折半插入排序在直接插入排序的基础上,确定待插入位置后,统一移动元素
代码实现
void InsertSort1(int A[], int n){
int i, j, high, low, mid;
for(i=2; i<=n; i++){
A[0] = A[i];
low = 1;
high = i-1;
while(low <= high){
mid = (high+low)/2;
if(A[mid] > A[0])
high = mid-1;
else
low = mid +1;
}
for(j=i-1; j>=high+1; --j)
A[j+1] = A[j];
A[high+1] = A[0];
}
}
举例
性能分析
- 时间复杂度:减少了比较元素的次数,约为
O
(
n
log
2
n
)
O(n\log_2n)
O(nlog2n),且次数与待排序表的初始状态无关。元素的移动次数并未改变,任然依赖于排序表的初始状态。时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)
- 稳定性:稳定
希尔排序
算法原理
- 取一个小于
n
n
n的步长
d
1
d_1
d1,把表中全部记录分成
d
1
d_1
d1组,所有距离为
d
1
d_1
d1的倍数的记录放在同一组,各组内进行直接插入排序
- 取第二个步长
d
2
<
d
1
d_2<d_1
d2<d1,重复上述步骤,直至所取到的
d
t
=
1
d_t=1
dt=1,即所有记录都在同一组中,再进行直接插入排序(已有较好的局部有序性)
代码实现
void ShellSort(int A[], int n){
int d, i, j;
for(d=n/2; d>=1; d=d/2)
for(i=d+1; i<=n; ++i)
if(A[i] < A[i-d]){
A[0] = A[i];
for(j=i-d; j>0&&A[0]<A[j]; j-=d)
A[j+d] = A[j];
A[j+d] = A[0];
}
}
举例
性能分析
- 空间复杂度:只使用了常数个辅助单元,空间复杂度为
O
(
1
)
O(1)
O(1)
- 时间复杂度:最坏情况下为
O
(
n
2
)
O(n^2)
O(n2)
- 稳定性:不稳定