数据结构学习——shell排序的C语言实现

摘要:
shell排序:  这个排序的命名是来自发明者的名字,和排序的方法没有字面上的联系。在K&R的C程序设计语言中书中只用了几行代码很简洁的实现了这个排序算法。编写程序时就是将我们所取的数和与他间隔为d大小的位置上的数比较。这边第一次组的数量是4,那么就是将第一个数和他间隔为4的数比较。用于互换两个数时的一个临时数。

shell排序:

  这个排序的命名是来自发明者的名字,和排序的方法没有字面上的联系。所以不要因为名字而感觉很难。在K&R的C程序设计语言中书中只用了几行代码很简洁的实现了这个排序算法。那就来看看这个排序是如何实现的。

原理:

  我们将所要排序的序列(大小为n)划分成组,组的数量一般是可以用这个序列的大小的一半来定义(也就是d = n/2),然后不断折半,而组的成员就是间隔为d的数分为一组。比如这边有个长度为8的数字序列要去排序,那我们就可以先将这个序列分成d=4组的,每个组有两个数,(这边的4就是8的一半)。这四组就是(R1,R5),(R2,R6),(R3,R7),(R4,R8).然后就是组内比较,如果前者大,交换他们的位置。以次类推。编写程序时就是将我们所取的数和与他间隔为d大小的位置上的数比较。这边第一次组的数量是4,那么就是将第一个数和他间隔为4的数比较。当第一次排序后,我们将这个间隔缩小,就是拿上一次组数d折半。那么这次的组就只有2个了。每个组有4个数.同样是和上面一样,间隔为d=2的位置上的数比较(实际上操作是这样的,但是我们可以认为他们已经是在一个组里面了,就可以说成组内比较)。我们知道d最后会变成1的,那会儿就是相邻的两个数比较,所有的数字都会放在正确的位置上的。原理基本是这样的。

实现:

  我们知道了原理,那就用自己熟悉的语言将其编写出来,我们这边是用的C语言,将其编写出来的。

  我们按照我们上述的原理将其一步一步的实现下:

1 //函数的参数包含两个,一个是要排序的数组,一个是数组的大小
2 //函数不使用额外的空间,只用到数组本身。这就要求数组在输入时候保留出
3 //R[0],R[0]就相当是一个temp。用于互换两个数时的一个临时数。
4 void shellsort(int R[],intn)
5 {
6     inti,j,d;
7     d = n/2;
8     while(d >= 1)
9 {
10         //注意i的起始和最后的那个“=,我们的第一个数是R[1],所以i-d要从1开始
11         for(i = d + 1;i <= n;i++)
12 {
13             j = i -d;
14             //将R[i]暂存
15             R[0] =R[i];
16             //这边的R[0]就是R[j+d]也就是R[i]
17             while(j>0 && R[j] > R[0])
18 {
19                 //将j位置的值给j+d位置
20                 R[j+d] =R[j];
21                 j -=d;
22 }
23             //这边就是对应着上面的j-=d,如果上面的while执行了,j
24             //位置的值已经给了j+d位置了,那么j+d的值也要给j位置,互换
25             //这就要求下标必须是对应的。所以要将j-d才能满足这边是R[j]
26             //如果while没有执行,那么还将原来的R[i]的值放到原来位置上
27             R[j+d] = R[0];
28 }
29         //d减半
30         d/=2;
31 }
32 }

上面就是按照所述的原理实现的,代码也不是很多,但是看上去有点乱,那么能不能改进点呢?下面就来了啊。

精简:

  我们一般在保证程序的可读上,将程序变得很精巧。这也是K&R的一个思想把。我们知道while和for在一定的情况下是可以替代的。所以我们可以将上述的程序,变得更为紧凑些,我们用三个for循环就可以了。下面是精简后的实现:

1 #include<stdio.h>
2 
3 #define N 100
4 void shellsort(int *,int);
5 
6 int main(void)
7 {
8     intv[N];
9     intn,i;
10 
11     printf("输入你数组的大小:");
12     scanf("%d",&n);
13 
14     printf("输入%d个数,空格隔开:
",n);
15     for(i = 0;i < n; i++)
16 {
17         scanf("%d",&v[i]);
18 }
19 
20 shellsort(v,n);
21     
22     printf("shell排序后:");
23     for(i =0;i < n;i++)
24 {
25         printf("%3d",v[i]);
26 }
27     
28     printf("");
29     return 0;
30 }
31 
32 void shellsort(int v[],intn)
33 {
34     inti,j,temp,gap;
35 
36     for(gap = n/2;gap > 0;gap /=2)
37         for(i =gap ;i < n ;i++)
38         for(j = i - gap;j>=0 && v[j] >v[j+gap]; j-=gap)
39 {
40             temp =v[j];
41             v[j] = v[j+gap];
42             v[j+gap] =temp;
43 }
44 }

这边我给出了一个完整的程序,不过我们只看函数的实现。上面的函数中,第一个for循环控制的是被比较数之间的间隔,也可以说是分组的依据。中间的循环是控制元素移动位置的。最后一个循环就是组内的比较,如果顺序不对就交换位置。将第一个函数里面的while整合成了for,这样看起来程序很精简,我们在理解上可能会有些卡壳,如果熟悉while和for之间转换的话就会好很多。

补充:

for(表达式1;表达式2;表达式3)

语句;

等价于while的为:

表达式1;

while(表达式2)

  {

    语句;

    表达式3;

  }

免责声明:文章转载自《数据结构学习——shell排序的C语言实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇array_walk() 函数BGP 实验下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ZeroMQ示例(C/C++/PHP)详解三种模式

源自:https://blog.csdn.net/qq_16836151/article/details/521081521、应答模式2、均衡分配模式(推拉模式)3、发布订阅模式(天气预报) 提问-回答 让我们从简单的代码开始,一段传统的Hello World程序。我们会创建一个客户端和一个服务端,客户端发送Hello给服务端,服务端返回World。下文是...

SQL Server 存储过程 数组参数 (How to pass an array into a SQL Server stored procedure)

Resource from StackOverflow 使用存储过程,如何传递数组参数? 1.分割解析字符串,太麻烦 2.添加Sql Server 自定义类型 **sp_addtype** 问题需求:需要向SP 传递数组类型的参数 select * from Users where ID IN (1,2,3 ) Sql Server 数据类型 并没...

微信小程序之条件判断

前文: 今天踩了一下午的坑,但是确实很简单的问题。 我说一下需求:扫描商品的二维码,从而判断,同一个二维码不可多次扫描; 点击扫一扫 会在灰色区域展示 扫描的商品信息,比如商品名称,商品码等,但是我们的需求是一物一码,即使是同一个商品也是不同的商品码。 错误示例: 最开始我的想法是做判断,因为我会在相对应的js文件中定义一个 productList:[...

Shell学习笔记——变量

变量赋值时不需要$符号,且=前后不能有空格 赋值时可以用=`命令`,将命令运行的结果值赋值过去,这里用到的是反引号 $0 $1 $2 - $9表示命令行的参数,并且可以通过shift将后面的参数移到前面来以获得更多参数 read可以读入参数,也可以通过重定向从文件读入,并且最后一个参数会把剩下所有内容读入,不够则为空串。IFS用于设置读取时候的分隔符。 $...

oracle 嵌套表 老猫

一、嵌套表的定义:     嵌套表是表中之表。一个嵌套表是某些行的集合,它在主表中表示为其中的一列。对主表中的每一条记录,嵌套表可以包含多个行。在某种意义上,它是在一个表中存储一对多关系的一种方法。考查一个包含部门信息的表,在任何时间内每个部门会有很多项目正在实施。在一个严格的关系模型中,将需要建立两个独立的表department和project.   ...

Docker学习—DockerFile

前言:  上一篇文章简单使用了docker 拉取镜像、启动容器、编译镜像;其中编译镜像时,使用到了Dockerfile,那么接下来我们就详细的来说说Dockerfile DockerFile是什么:   Dockerfile 是一个用来构建镜像的文本文件,Dockerfile内容中包含了一条条构建镜像所需的指令和说明。最终采用docker build 命令...