明白了线性表的逻辑结构后,编程时的很多问题与此类似时,就可以抽象为线性表。
在用线性表上的运算方法进行运算。
在易语言中线性表的存储方式就是用一维数组。
所以,我们把一维数组称为线性表。
以后线性表上的运算,都是通过一维数组完成。
线性表的其它存储结构在易语言中不易实现,不再我们现在的研究范围。
关于结点
线性表是由一个个结点组成,结点间的邻接关系就构成线性表的逻辑结构。
其内容我们以讲过。
结点是什么呢?
结点是数据的载体,它可以是简单的变量类型,更多时候是复杂的自定义数据类型的变量。
线性表的运算。
易语言以提供了一维数组的运算方法。
我们现在研究他们到底是怎么实现的。
理由就是,很多时候结点是很复杂的自定义数据类型的变量,这时的一维数组就无法用易语言提供的运算命令进行计算,这时就需要我们自己来写。
线性表上的运算是最简单的,也是每个想学算法的人首先和必需掌握的。
下节我们在讲吧。
^_^
易语言算法入门(5)排序算法
(一)
从本节开始我们我们慢慢增加算法的难度。
我们讲的算法都是编程中一些常用的算法,都是一些有共性的东西。
这些东西学会了,编程水平自然会上一个层次。
本节讲排序运算。
首先讲插入排序法。
插入排序的基本思想是:
每次把一个待排序的结点,按其关键字的大小插入到前面已排序好结点中,直到全部结点插入完毕。
1.直接插入排序法
两个重要概念。
有序区:
是指顺序表中已排序好的部分。
无序区:
即表中未进行排序的区域。
例如,一维数组[2,5,6,2,9,5,47]有序区的范围是:
【1,3】(从1到3结点),无序区是:
【4,7】(从4到7结点)。
对于任何一个结点为n(n>1)的顺序表,其初始有序区的范围是【1,1】无序区的范围是【2,n】。
大家能否理解呢?
(道理很简单,一个结点自然是有序的。
)插入排序的基本思想就是不断增大有序区,减小无序。
直到无序区消失。
直接插入排序的原理:
每次将无序区的第一个结点插入到有序区中。
例,无序数组[8,5,6,4,3,9,4],其初始有序区【1,1】,无序区【2,7】,
第一次插入运算,将无序区第一个结点“5”查到前面的有序区中。
运算后数组为[5,8,6,4,3,9,4],有序区为【1,2】无序区为【3,7】。
第二次插入运算,将无序区的第一个结点“6”插入到前面的有序区中,运算后的数组为[5,6,8,4,3,9,4],其有序区为【1,3】,无序区减小成【4,7】。
如此重复,经过6次插入运算,有序区成为【1,7】,无序区消失。
此数组成为有序数组。
程序代码:
子程序:
直接插入排序
参数:
欲操作数组数据类型:
整数型<参考>,<数组>
局部变量:
结点个数数据类型:
整数型//:
数组的长度
局部变量:
无序区首数据类型:
整数型//:
指向无序区第一个结点的指针。
局部变量:
插入点数据类型:
整数型//:
将无序区第一个结点插入到有序区中的位置
局部变量:
暂存容器数据类型:
整数型//:
暂时存放无序区第一个结点的数据,
局部变量:
移动点数据类型:
整数型//:
移动数据时的控制变量结点个数=取数组成员数(欲操作数组)
如果真(结点个数≤1)
返回()
如果真结束
变量循环首(2,结点个数,1,无序区首)//:
需要进行n-1次插入运算。
计次循环首(无序区首-1,插入点)//:
在有序区中寻找插入位置。
如果真(欲操作数组[无序区首]≤欲操作数组[插入点])//:
此为升序排序的插入条件。
跳出循环()//:
找到了插入位置。
如果真结束
计次循环尾()
暂存容器=欲操作数组[无序区首]
变量循环首(无序区首,插入点+1,-1,移动点)//:
前面讲的插入运算
欲操作数组[移动点]=欲操作数组[移动点-1]
变量循环尾()
欲操作数组[插入点]=暂存容器
变量循环尾()
本段代码用到了前面讲的查找算法和插入算法。
掌握一些基本算法,可以提高编程能力。
练习:
去掉数组中重复的数据,即数组中没有重复的数据。
易语言算法入门(5)排序算法
(二)
讨论上节未讲完的内容。
直接插入排序法的代码在执行过程中,大部分时间是消耗在查找插入点位置和移动结点上。
结点的移动是必须的,此类算法是无法减少移动次数的,除非是用新的算法。
而每次都从无序区首(即表的第一个结点)开始寻找插入点的过程是完全没有必要的,可以用我们讲过的二分查找法优化此过程。
二分查找法我和老鸟都讲过,此处不再重复。
以下是实现代码,c语言算法书上是没有的,是俺活学活用的即兴之做。
子程序:
二分直接插入排序
参数:
欲操作数组数据类型:
整数型<参考>,<数组>
局部变量:
结点个数数据类型:
整数型
局部变量:
无序区首数据类型:
整数型
局部变量:
插入点数据类型:
整数型
局部变量:
暂存容器数据类型:
整数型
局部变量:
移动点数据类型:
整数型
局部变量:
首位置数据类型:
整数型
局部变量:
末位置数据类型:
整数型
局部变量:
中间位置数据类型:
整数型结点个数=取数组成员数(欲操作数组)
如果真(结点个数≤1)
返回()
如果真结束
变量循环首(2,结点个数,1,无序区首)
首位置=1
末位置=无序区首-1
判断循环首(首位置≤末位置)
中间位置=取整((首位置+末位置)÷2)
如果(欲操作数组[无序区首]<欲操作数组[中间位置])
插入点=中间位置
末位置=中间位置-1
否则
如果(欲操作数组[无序区首]>欲操作数组[中间位置])
首位置=中间位置+1
否则
插入点=中间位置
跳出循环()
如果结束
如果结束
判断循环尾()
如果真(插入点≠0)
暂存容器=欲操作数组[无序区首]
变量循环首(无序区首,插入点+1,-1,移动点)
欲操作数组[移动点]=欲操作数组[移动点-1]
变量循环尾()
欲操作数组[插入点]=暂存容器
插入点=0
如果真结束
变量循环尾()
易语言算法入门(5)排序算法(三)
上节对直接插入排序进行了优化,我们暂且把优化算法称为二分直接插入排序,这种算法仅仅事对寻找插入点的过程做了优化。
如果我们能找到另一中方法,可同为减少寻找插入点的次数和移动结点的次数,就可显著的提高排序的运算速度。
本节介绍的希尔排序算法是直接插入排序法的一种变种,它能有效的减少这两个方面的运算量,从而显著的提高排序操作的运算速度。
原理:
先取一个小于结点数的整数k作为分组单位,把表上的所有相距k的结点逻辑上看成一组。
在个组内进行直接插入排序;减小k的取值,把表上的所有相距k的结点逻辑上看成一组。
在个组内进行直接插入排序;重复以上步骤;最后一次k取1,即对整个表做直接插入排序。
其中k称为增量,增量的取值集合称为增量表。
例,无序数组[4,5,8,2,6,8,9,2,4,5,1,6,1,5,4,2]增量表我们取成“5,3,1”(k的取值集合)1.当k=5为,表上的逻辑分组情况为:
【1,6,11。
16】【2,7,12】【3,8,13】【4,9。
14】【5,10,15】(【】内均是数组的下标值)。
k=5为的组内进行直接插入排序过程为:
第一组:
数组成员分别为“4”,“8”,“1”,“2”。
排序后的数组[1,5,8,2,6,2,9,2,4,5,4,6,1,5,4,8]
第二组:
数组成员分别为“5”,“9”,“6”。
排序后的数组[1,5,8,2,6,2,6,2,4,5,4,9,1,5,4,8]
第三组:
数组成员分别为“8”,“2”,“1”。
排序后的数组[1,5,1,2,6,2,6,2,4,5,4,9,8,5,4,8]
第四组:
数组成员分别为“2”,“4”,“5”。
排序后的数组[1,5,1,2,6,2,6,2,4,5,4,9,8,5,4,8]
第五组:
数组成员分别为“6”,“5”,“4”。
排序后的数组[1,5,1,2,4,2,6,2,4,5,4,9,8,5,6,8]
此趟运算后数组为[1,5,1,2,4,2,6,2,4,5,4,9,8,5,6,8]2.当k=3为,表上的逻辑分组情况为:
【1,4,7,10,13,16】【2,5,8,11,14】【3,6,9,12,15】(【】内均是数组的下标值)。
k=3为的组内进行直接插入排序过程为:
第一组:
数组成员分别为“1”,“2”,“6”,“5”,“8”,“8”
排序后的数组[1,5,1,2,4,2,5,2,4,6,4,9,8,5,6,8]
第二组:
数组成员分别为“5”,“4”,“2”,“4”,“6”。
排序后的数组[1,2,1,2,4,2,5,4,4,6,5,9,8,6,6,8]
第三组:
数组成员分别为“1”,“2”,“4”,“9”,“6”。
排序后的数组[1,2,1,2,6,2,6,2,4,5,4,6,8,5,9,8]
此趟运算后数组为[1,2,1,2,6,2,