直接插入排序与我们生活中打扑克牌非常相似1.直接插入排序的原理你现在有三张手牌:1,4,6,7,当我们再次抽到 3 这张牌时,往往会习惯性的将他插入到 1 和 4 之间。
这个过程就是一次直接插入排序。
已知一段有序的序列,将序列以外的数据插入有序序列中,使得其变成一个新的有序序列
排序过程
已知序列 { 0,4,5,8,9,3,6,2 }
先从第一个数入手,后一个数与之比较
若后一个数小于前一个数,则交换。
以此类推
序列 { 0 } 4 4 > 0 不插入
序列 { 0,4 } 5 5 > 4 > 0 不插入
序列 { 0,4,5 } 8 8 > 5 > 4 > 0 不插入
序列 { 0,4,5,8 } 9 9 > 8 > 5 > 4 > 0 不插入
序列 { 0,4,5,8,9 } 3 9 > 8 > 5 > 4 > 3 > 0 插入于0后
序列 { 0,3,4,5,8,9 } 6 9 > 8 > 6 > 5 > 4 > 3 > 0 插入于5后
序列 { 0,3,4,5,6,8,9 } 2 9 > 8 > 6 > 5 > 4 > 3 > 2 > 0 插入于0后
图解
2.代码实现
#include
void ArrPrint(const int* a, int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
}
void InsertSort(int* a, int n)
{
int i = 0;
for (i = 0; i < n - 1; i++) //for循环遍历数组元素
{
int end = i; //用临时变量end来决定每一步排序开始的位置
int tmp = a[end + 1]; //用临时变量tmp来存放end的下一个元素的值
while (end >= 0) //若end小于0则end已超出数组范围,需跳出while循环
{
if (tmp < a[end]) //如果tmp的值小于end,则end向后移动一位 (将 < 改为 > 可变为降序)
{
a[end + 1] = a[end];
end--; //end往前移,使得前一个元素标记为新的end
}
else //若tmp的值大于end,则跳出while循环
{
break;
}
}
a[end + 1] = tmp; //将tmp插入到end的后一位
}
}
int main()
{
int arr[] = { 0,4,5,8,9,3,6,2 }; //测试用例
InsertSort(arr, sizeof(arr) / sizeof(arr[0]));
ArrPrint(arr, sizeof(arr) / sizeof(arr[0]));
return 0;
}
代码注意事项
1. i 的限制
i 的取值会之间影响到 end ,end 的取值会影响到 tmp,所以若 i 的取值不加以限制,很可能会导致数组的越界访问。
2.将 tmp 插入放在 while 循环外的妙处
3.时间复杂度分析--- 当 tmp 的值小于他前面所有的元素的值时,经过 while 循环后,end = -1,跳出 while 循环执行a[end+1] = tmp; 语句,恰好将 tmp 置于数组首元素位置,即a[0] = tmp
--- 当 tmp 的值大于 a[end] 的值时 while 循环内部会执行 else 语句的内容,即 break,跳出 while 循环执行a[end+1] = tmp; 语句,此时也满足排序的目的将 tmp 插入 a[end] 后
当最好情况,也就是排序表本身就是有序的,则只需要进行 n-1 次比较,由于每次都是 arr[i] > arr[i+1],没移动记录,时间复杂度为 O(n)。
最坏的情况下,是排序表逆序,需要比较 (n+2)(n-1) / 2 次,移动 (n+4)(n-1) / 2 次。
如果排序记录是随机的,根据概率相同的原则,平均比较和移动的次数约为 n^2 / 4 次。
因此,直接插入排序算法时间复杂度为 O(n^2)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)