• 数据结构-插入排序


    插入排序

    插入排序的三种常见方法:

    直接插入排序、折半插入排序、希尔排序。

    数据存储结构

    因为我们是用的是C语言来实现算法,因此我们需要创建一个结构体,用来存放初始数据。

    结构体定义如下:

    1. #define MAX 100
    2. typedef int KeyType;
    3. typedef struct{
    4. KeyType key;
    5. }RecordType;
    6. typedef struct{
    7. RecordType R[MAX+1];
    8. int length;
    9. }OrderList;

    示例数据

     

    其中data[0]置为0,用来表示哨兵单元。

    直接插入排序

    基本思想

    当插入第i个记录时,前面的R[1]....R[i-1]已经排好序,这时用R[i]依次与前面的关键字比较,直到找

    到合适的位置,随后插入。

    代码实现

    1. OrderList InsertSort(OrderList L) //直接插入排序
    2. {
    3. int i,j;
    4. for(i=2;i<=10;i++){
    5. L.R[0] = L.R[i]; //L[0]做哨兵单元,同时也用来存放当前i位置记录大小.
    6. j = i - 1; //从i单元的前一个单元开始比较.
    7. while(L.R[0].key//升序
    8. L.R[j+1] = L.R[j]; //记录依次后移,其中最前面的记录永远会存在连续的两个.
    9. j = j - 1; //j需要前移继续比较.
    10. }
    11. L.R[j+1] = L.R[0]; //j+1为合适的位置.
    12. }
    13. return L;
    14. }

    验证

    复杂度

    时间复杂度为:O(_N{2})

    空间复杂度一直为:O(1)

    折半插入排序

    基本思想

    折半插入排序跟前面的折半查找有同曲异工之妙,其中在查找的时候不再是顺序查找,而是折半查

    找,但是在数据移动的过程中,仍然是顺序移动下来。

    代码实现

    1. OrderList BinsertSort(OrderList L) //折半插入排序
    2. {
    3. int i,j,low,high,mid;
    4. for(i=2;i<=L.length;i++){
    5. L.R[0] = L.R[i];
    6. low = 1;
    7. high = i - 1; //上界应该为i单元的前一个单元位置
    8. while(low <= high){
    9. mid = (low+high) / 2;
    10. if(L.R[0].key < L.R[mid].key)
    11. high = mid - 1;
    12. else
    13. low = mid + 1;
    14. } //待插入的位置一定是low的位置,
    15. for(j=i-1;j>=low;j--) //i单元前面的所有单元依次后移.
    16. L.R[j+1] = L.R[j];
    17. L.R[low] = L.R[0]; //插入单元
    18. }
    19. return L;
    20. }

    验证

    复杂度

    若待排序列为正序,则时间复杂度为:O(N)

    若待排序列为逆序,则时间复杂度为:O(_N{2})

    空间复杂度一直为:O(1)

    希尔排序

    希尔排序又叫做“缩小增量排序”。

    基本思想

    先将整个记录序列分割成若干个子序列,分别进行直接插入排序,在整个序列中的记录“基本有序”

    时,再对全体记录进行一次直接插入排序。

    其中,子序列并不是进行简单的分割,而是将某个增量d的记录组成一个子序列,让增量d逐步缩

    短,直到d=1为止。

    d的选取有很多种方法,这里只简单说明最基本的一种(足以应对绝大多数情景):

    d = [n/2]--------->d = [d/2]

    下面我们给出一个例子:

    假定有一个数据序列为:{5,9,12,2,8,15}

    我们来看看希尔排序的一个完整过程:

    1.d = [6/2] = 3

    将整个序列分为三个子序列:{5,2}、{9,8}、{12,15}。

    对三个子序列分别进行直接插入排序,得到新的三个子序列:

    {2,5}、{8,9}、{12,15}

    由这三个子序列拼凑成一个新的序列为:

    {2,8,12,5,9,15}

    2.d = [3/2] = 1

    此时d = 1,所以直接对整个序列{2,8,12,5,9,15}进行一次直接插入排序,即可获得最终结果。

    代码实现

    1. OrderList ShellSort(OrderList L)
    2. {
    3. int i,j,d;
    4. RecordType tmp;
    5. for(d=L.length/2;d>0;d/=2){ //d为本趟希尔排序的增量
    6. for(i=d+1;i<=L.length;i++){
    7. tmp = L.R[i]; //保存待插入单元
    8. j = i - d; //j是与i间隔为d的前一个单元
    9. while(j>=1&&tmp.key
    10. L.R[j+d] = L.R[j]; //R[j]必须后移d个位置,因为比较单元间相隔d
    11. j = j - d;
    12. }
    13. L.R[j+d] = tmp;
    14. }
    15. }
    16. return L;
    17. }

    验证

    复杂度

    时间复杂度为:O(^{N^{1.3}})

    空间复杂度一直为:O(1)

    所有代码

    1. #include
    2. #define MAX 100
    3. typedef int KeyType;
    4. typedef struct{
    5. KeyType key;
    6. }RecordType;
    7. typedef struct{
    8. RecordType R[MAX+1];
    9. int length;
    10. }OrderList;
    11. OrderList InsertSort(OrderList L) //直接插入排序
    12. {
    13. int i,j;
    14. for(i=2;i<=10;i++){
    15. L.R[0] = L.R[i]; //L[0]做哨兵单元,同时也用来存放当前i位置记录大小.
    16. j = i - 1; //从i单元的前一个单元开始比较.
    17. while(L.R[0].key//升序
    18. L.R[j+1] = L.R[j]; //记录依次后移,其中最前面的记录永远会存在连续的两个.
    19. j = j - 1; //j需要前移继续比较.
    20. }
    21. L.R[j+1] = L.R[0]; //j+1为合适的位置.
    22. }
    23. return L;
    24. }
    25. OrderList BinsertSort(OrderList L) //折半插入排序
    26. {
    27. int i,j,low,high,mid;
    28. for(i=2;i<=L.length;i++){
    29. L.R[0] = L.R[i];
    30. low = 1;
    31. high = i - 1; //上界应该为i单元的前一个单元位置
    32. while(low <= high){
    33. mid = (low+high) / 2;
    34. if(L.R[0].key < L.R[mid].key)
    35. high = mid - 1;
    36. else
    37. low = mid + 1;
    38. } //待插入的位置一定是low的位置,
    39. for(j=i-1;j>=low;j--) //i单元前面的所有单元依次后移.
    40. L.R[j+1] = L.R[j];
    41. L.R[low] = L.R[0]; //插入单元
    42. }
    43. return L;
    44. }
    45. OrderList ShellSort(OrderList L)
    46. {
    47. int i,j,d;
    48. RecordType tmp;
    49. for(d=L.length/2;d>0;d/=2){ //d为本趟希尔排序的增量
    50. for(i=d+1;i<=L.length;i++){
    51. tmp = L.R[i]; //保存待插入单元
    52. j = i - d; //j是与i间隔为d的前一个单元
    53. while(j>=1&&tmp.key
    54. L.R[j+d] = L.R[j]; //R[j]必须后移d个位置,因为比较单元间相隔d
    55. j = j - d;
    56. }
    57. L.R[j+d] = tmp;
    58. }
    59. }
    60. return L;
    61. }
    62. int main()
    63. {
    64. OrderList sample;
    65. sample.length = 10;
    66. int i,data[11]={0,5,8,4,12,35,6,8,67,64,100};
    67. for(i=1;i<11;i++)
    68. sample.R[i].key = data[i];
    69. sample = ShellSort(sample);
    70. for(i=1;i<11;i++)
    71. printf("%d ",sample.R[i].key);
    72. return 0;
    73. }

  • 相关阅读:
    Springboot日常总结-idea全局配置maven
    Vue $nextTick
    图片铺满div元素不变形,超出部分隐藏,保留中心部分css代码
    ISO 8601持续时间格式
    MogaFX外汇市场保持相对稳定
    微信网页支付小白指南-域内浏览器支付 + 外部浏览器支付
    NPDP为什么越来越受追捧?产品经理你可知道?
    CC攻击演示
    STM32 CAN/CANFD软件快速配置(HAL库版本)
    Diffle-Hellman Key Exchange密钥交换
  • 原文地址:https://blog.csdn.net/zheshiyangyang/article/details/134518498