本内容是笔者结合《数据结构(C语言版)》(严蔚敏)总结所得,记录学习过程,分享知识!
目录:
1. 插入排序分析(大白话解释)
2. 插入排序实现
- - 2.1 单次插入模拟实现
- - 2.2 插入排序实现
- - 2.3 可执行完整程序代码及结果展示
3. 插入排序总结
4. 结语及相关推荐(排序汇总)
1. 插入排序分析(大白话解释)
(大白话解释示例)插入排序就好比打麻将时,你手握清一色的饼牌(万牌、条牌),当你抽到同种牌时会看牌的大小,然后将其插入到你已有的手牌,使手牌始终有序。(当然如果你打牌、麻将从不对同型牌排序就当我没说)
插入排序规则,即在一个待排序序列中:
- 始终维护一个有序序列,序列大小可以是 1(即只有一个元素);
- 通常该部分有序序列总在序列从左至右(起始 => 结束);
- 总是选择部分有序序列后的第一个值进行插入操作,假设:有序部分的最后一个元素的索引为 end,则待插入元素索引为:end+1;
- 待插入元素 arr[end+1],逆序依次向前比较,若符合插入条件则插入序列。
- 重复步骤,直至排序结束!
图示如下:
2. 插入排序实现
2.1 单次插入模拟实现
1. 明确 end 的初值!为了部分有序时,第一次进入排序可设置为:0
2. 由于排序插入过程中,我们实现的是移动覆盖!故需要暂存待排序值!
3. 注意迭代 end!对比插入向前搜索时,end 同时用于标识当前比较对象,显然根据索引非负易得循环条件!
4. 数据插入!(注意插入位置!建议手动画图理解!)
int end = 0; // 用于标识数组中已有序序列的位置:[0,end]已有序,从 end+1 开始待排序
int temp = array[end+1]; // 暂存待排序值
while(end >= 0){
if( temp < array[end] ){
array[end+1] = array[end]; // 向后覆盖 / 移动操作!
--end; // 向前搜索
}
else{
break;
}
}
array[end+1] = temp; // 数据插入!
2.2 插入排序实现
实现单次插入排序操作之后,继续分析。显然每次插入完成之后,我们原有的“部分有序序列”会增大一个单位!
实际,要对所有元素进行一次插入操作,只需遍历一遍数组即可!
注意点:由于我们标识待插入元素索引的标识方式为:end+1,故需要注意越界问题!!!
【 完整代码如下: 】
void InsertSort(DataType* array, int size) {
// 注意循环次数!与代码实现有关!
for (int i = 0; i < size - 1; i++) {
int end = i; // 用于标识数组中已有序序列的位置:[0,end]已有序,从 end+1 开始待排序
DataType temp = array[end + 1]; // 标识当前被操作对象(插入对象)
// 单次插入过程
while (end >= 0) {
if (temp < array[end]) {
array[end + 1] = array[end];
--end;
}
else {
break;
}
}
array[end + 1] = temp;
}
}
2.3 可执行完整程序代码及结果展示
#pragma
#include<stdio.h>
/* 本篇内容将实现:C 语言版顺序存储:插入排序 */
#include<stdio.h>
typedef int DataType;
/* 打印函数 */
void PrintArray1(DataType* array, int size);
void PrintArray2(DataType* array, int size); // 测试字符排序
/* 顺序存储插入排序: */
/* 参数说明:被操作数组;数组大小 */
void InsertSort(DataType* array, int size);
/* 打印函数 */
void PrintArray1(DataType* array, int size) {
printf("array:");
for (int i = 0; i < size; i++)
printf("%d ", array[i]);
printf("\n");
}
void PrintArray2(DataType* array, int size) {
printf("array:");
for (int i = 0; i < size; i++)
printf("%c ", array[i]);
printf("\n");
}
/* 顺序存储插入排序: */
/* 参数说明:被操作数组;数组大小 */
/* 时间复杂度: O(N^2)
最优:O(N)
最差:O(N^2)
*/
void InsertSort(DataType* array, int size) {
for (int i = 0; i < size - 1; i++) {
int end = i; // 用于标识数组中已有序序列的位置:[0,end]已有序,从 end+1 开始待排序
DataType temp = array[end + 1]; // 标识当前被操作对象(插入对象)
// 单次插入过程
while (end >= 0) {
if (temp < array[end]) {
array[end + 1] = array[end];
--end;
}
else {
break;
}
}
array[end + 1] = temp;
}
}
void test_InsertSort() {
#if 1
printf("============================================================\n");
printf("整型测试用例:\n");
int a[] = { 5,3,6,44,8,2,2,64,85,16,48,46,846,4,6843,54,846,16,48,4,1,64,684,6,46 };
int size = sizeof(a) / sizeof(int);
PrintArray1(&a, size);
InsertSort(&a, size);
PrintArray1(&a, size);
#else
printf("============================================================\n");
printf("字符型测试用例(注:需将 typedef int DataType; 改成:typedef char DataType;才可正常):\n");
char b[] = "qwertyuiopasdfghjklzxcvbnm";
int size = sizeof(b) / sizeof(char);
PrintArray2(b, size);
InsertSort(b, size);
PrintArray2(b, size);
#endif
}
int main() {
test_InsertSort();
return 0;
}
测试结果展示:
3. 插入排序总结
关于时间复杂度:O(N^2)
- 最优:O(N) 【待排序序列为有序】;
- 最差:O(N^2) 【待排序序列恰好为逆序】
关于优化:
由上可知,当原序列有序程度越高,插入排序效率越高!若能对原序列进行预排序(通过简单操作使原序列有序程度提高!)实质上希尔排序就是对插入排序有序化在插入的优化排序!