详解希尔排序——附图片代码

算法思想

希尔排序是特殊的插入排序,直接插入排序每次插入前的遍历步长为1,而希尔排序是将待排序列分为若干个子序列,对这些子序列分别进行直接插入排序,当每个子序列长度为1时,再进行一次直接插入排序时,结果一定是有序的。
常见的划分子序列的方法有:初始步长(两个子序列相应元素相差的距离)为要排的数的一半,之后每执行一次步长折半。

思路

  1. 先追求表中元素的部分有序,再逐渐逼近全局有序
  2. 更适用于基本有序的排序表和数据量不大的排序表,仅适用于线性表为顺序存储的情况

预排序:

将无序序列以d为间隔进行分组,所有间隔相同的为一组,分别对每组进行直接插入排序。

  - 本次需要排序的数的数量为n,n为10。
  - 先进行预排序,使原序列更接近有序序列,最后将预排之后的序列进行直接插入排序。  
  -  d的初值为需要排序的数的数量的一半,d=n/2,d=5,就是相隔五个数的值作为一个子组,先对子组的数值进行插入排序

图解

在这里插入图片描述

  - 第一次排序时,d=n/2=5,每次间隔5个数的值组成一个子组,对子组的数据进行插入排序
  - 第二次排序时,d=d/2=2,   每次间隔2个数的值组成一个子组,对子组的数据进行插入排序
  - 第3次排序时,d=d/2=1,   最后当d=1时,完成了预排序,最后进行一遍插入排序,就可以完成本次的希尔排序

代码演示

#include <stdio.h>
#include <malloc.h>

void shellSort(int *a, int len); // 函数声明

int main(void)
{
    int i, len, * a;
    printf("请输入要排的数的个数:");
    scanf("%d",&len);
    a = (int *)malloc(len * sizeof(int)); // 动态定义数组
    printf("请输入要排的数:\n");
    for (i = 0; i < len; i++) { // 数组值的输入
        scanf("%d",&a[i]);
    }
    shellSort(a, len); // 调用希尔排序函数
    printf("希尔升序排列后结果为:\n");
    for (i = 0; i < len; i++) { // 排序后的结果的输出
        printf("%d\t",a[i]);
    }
    printf("\n");

    return 0;
}

void shellSort(int *a, int len)
{
    int i, j, k, tmp, d;  // d 为步长
    for (d = len / 2; d > 0; d /= 2) {  // 步长初始化为数组长度的一半,每次遍历后步长减半,
    	for (i = 0; i < d; ++i) { // 变量 i 为每次分组的第一个元素下标
	        for (j = i + d; j < len; j += d) { //对步长为d的元素进行直插排序,当d为1时,就是直插排序
	            tmp = a[j];  // 备份a[j]的值
	            k = j - d;  // j初始化为i的前一个元素(与i相差d长度)
	            while (k >= 0 && a[k] > tmp) {
	                a[k + d] = a[k]; // 将在a[i]前且比tmp的值大的元素向后移动一位
	                k -= d;
	            }
	            a[k + d] = tmp;
	        }
	    }
    }
}

效果展示

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值