排序
插入排序
一.顺序存储结构的直接插入排序(不带哨兵)
1.算法思想
插入排序是一种简单的排序算法,它的基本思想是将待排序的元素按照大小依次插入到已经排好序的序列中,直到所有元素都被插入完毕。具体实现时,可以从第二个元素开始,将其与前面已经排好序的元素进行比较,如果比前面的元素小,则将其插入到合适的位置,否则继续向后比较,直到找到合适的位置为止。时间复杂度为O(n^2),但对于小规模数据或者基本有序的数据表现较好
2.算法实现流程
数组
可以从第二个元素开始,将其与前面已经排好序的元素进行比较,如果比前面的元素小,则将其插入到合适的位置,否则继续向后比较
第一趟排序
38和49比较
38小于49
用个临时变量temp暂存38,然后将49后移一位
此时数组变成
第二轮排序,49和65比较,65大于49,不进入后移的循环,直接进入下一轮排序
第三轮排序 65和97比较,97大于65,不进入后移的循环,直接进入下一轮排序
第四轮排序 97和76比较,76小于97,进入后移循环,用temp暂存76,97后移一位,76跟65比较,76大于65跳出循环将76赋值到97的位置
第五轮排序 97跟13比较,13小于97,用temp暂存13,进入后移循环,将97往后移动,然后继续让13跟97前面的有序数组比较,直到找到小于13的元素或者到达了下标为0的位置,就进行插入操作
,
第六轮排序 97和27比较, 27小于97,进入后移的循环,直到找到小于27的13停止后移的循环,将temp插入到13的后面
第七轮排序97跟49比较,49小于97,进入后移的循环,这里匹配到49就会跳出循环,将49之后的元素都想后移动一位,把49插入到 49后面
排序完成
3.伪代码实现
#include<stdio.h>
void sort(int arr[],int sz)
{
int i = 1;
int j = 0;
int temp = 0;//存放要进行插入操作的变量
for (i = 1; i < sz; i++)
{
if (arr[i]< arr[i-1])//后一个元素大于前一个元素时,要进入后移循环
{
temp = arr[i];
for (j = i - 1; j >= 0 && arr[j] > temp; --j)//让比temp大的数都往后移
{
arr[j+1] = arr[j];
}
arr[j+1] = temp;
}
}
for (i = 0; i < sz; i++)
{
printf("%d ", *(arr + i));
}
}
ps:上面使用–j和j–都是一样的在for循环中没有区别
//输出结果
二.顺序存储结构的直接插入排序(带哨兵)
带哨兵的算法流程和不带哨兵的算法流程大致是一样的,只不过带哨兵的方法是不给数组第一个元素放数据,让首元素这个位置做哨兵,而不带哨兵就是声明一个临时变量来暂存要进行排序的元素在进行后移和插入操作,其实不带哨兵在后移时要限制好后移元素的界限不可越栈而使得后移这里形成死循环,因此可以看到我们上面有一个j>=0的限制判断,而带有哨兵的直接插入排序就避免了此问题
1.带哨兵的直接插入伪代码实现
#include<stdio.h>
void sort(int arr[], int sz)
{
int i = 0;
int j = 0;
for (i = 2; i <= sz; i++)
{
if (arr[i] < arr[i - 1])
{
arr[0] = arr[i];
for (j = i - 1; arr[0] < arr[j];j--)
{
arr[j + 1] = arr[j];
}
arr[j + 1] = arr[0];
}
}
}
三.折半插入排序
折半插入排序是一种插入排序的变体,它通过二分查找来寻找插入位置,从而减少了比较和移动的次数。具体实现步骤如下:
1.将第一个元素看作已排序的序列。
2.依次将后面的元素插入到已排序的序列中。
3.对于每个待插入的元素,使用二分查找在已排序的序列中找到插入位置。
4插入元素到找到的位置,并将该位置后面的元素向后移动一个位置。
5.重复步骤2-4,直到所有元素都被插入到已排序的序列中。折半插入排序是一种插入排序的变体,它通过二分查找来寻找插入位置,从而减少了比较和移动的次数。
初始化数组的时候第一个不存数据,作为哨兵
第一轮循环
i=1
key =49 ,left =0; right =0 ,进入while循环,mid =0+0/2=0 此时arr[mid]=0小于key,left=0+1,跳出while循环
j =1-1=0 right =0+1 =1 把0放到49的位置,跳出循环再把key放到49的位置
第二轮循环
i=2
key =38 left =0,right =1 进入while循环 mid = (1+0)/2=0 进入到else判断语句 left = 1 继续whille循环mid =1;
此时arr[mid]>key,则right =1-1=0;跳出循环j =2-1 ,:j>=1;循环一次将49移动到38的位置,跳出循环,将key放到49的位置
.
.
.
其他循环也是同理得出
void insert_sort(int arr[], int sz)
{
for (int i = 1; i < sz; i++)
{
int key = arr[i];
int left = 0;
int right = i - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] > key)
right = mid - 1;
else
left = mid + 1;
}
for (int j = i - 1; j >= right + 1; j--)
{
arr[j + 1] = arr[j];
}
arr[right + 1] = key;
}
for (int i = 1; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
运行结果
四.总结:
插入排序是一种简单但有效的排序算法,其基本思想是将待排序的元素逐个插入到已排序序列中的合适位置。具体实现时,可以采用循环嵌套的方式,外层循环遍历待排序序列,内层循环从后往前遍历已排序序列,找到插入位置并将元素插入。
插入排序的时间复杂度为 O(n^2),空间复杂度为 O(1)。虽然时间复杂度比较高,但对于小规模数据和部分有序的数据,插入排序表现良好。另外,插入排序是稳定排序,不会改变相等元素的相对顺序。
在实际应用中,为了提高插入排序的效率,可以采用优化策略,如二分查找插入位置、使用哨兵减少判断次数等。