我用 Python,3分钟快速实现,9 种经典排序算法的可视化

论坛 期权论坛 期权     
Python开发者   2019-1-24 00:49   3715   0
(给Python开发者加星标,提升Python技能)
作者:恋习Python/丁彦军 (本文来自作者投稿)
最近在某网站上看到一个视频,是关于排序算法的可视化的,看着挺有意思的,也特别喜感。

6分钟演示15种排序算法

[iframe]https://v.qq.com/iframe/preview.html?width=500&height=375&auto=0&vid=t0396emm8oy[/iframe]
不知道作者是怎么做的,但是突然很想自己实现一遍,而且用python实现特别快,花了一天的时间,完成了这个项目。主要包括希尔排序(Shell Sort)、选择排序(Selection Sort)、快速排序(Quick Sort)、归并排序(Merge Sort)等九种排序。

附上源码链接:
https://github.com/ZQPei/Sorting_Visualization
(觉得不错,记得帮忙点个star哦)

[h1]下面具体讲解以下实现的思路,大概需要解决的问题如下:[/h1]
  • 如何表示数组
  • 如何得到随机采样数组,数组有无重复数据
  • 如何实现排序算法
  • 如何把数组可视化出来

[h1]一、如何表示数组[/h1]
python提供了list类型,很方便可以表示C++中的数组。标准安装的Python中用列表(list)保存一组值,可以用来当作数组使用,不过由于列表的元素可以是任何对象,因此列表中所保存的是对象的指针。这样为了保存一个简单的[1,2,3],需要有3个指针和三个整数对象。对于数值运算来说这种结构显然比较浪费内存和CPU计算时间,再次就不详细论述。

[h1]二、如何得到随机采样数组,数组有无重复数据[/h1]
假设我希望数组长度是100,而且我希望数组的大小也是在[0,100)内,那么如何得到100个随机的整数呢?可以用random库。

示例代码:
  1. importrandom
  2. data=list(range(100))
  3. data=random.choices(data,k=100)
  4. print(data)
  5. [52,33,45,33,48,25,68,28,78,23,78,35,24,44,69,88,66,29,82,77,84,12,19,10,
  6. 27,24,57,42,71,75,25,1,77,94,44,81,86,62,25,69,97,86,56,47,31,51,40,21,41,
  7. 21,17,56,88,41,92,46,56,80,23,70,49,96,83,54,16,36,82,24,68,60,16,98,16,81,
  8. 10,13,11,24,68,35,56,39,23,44,6,30,3,60,56,66,38,28,47,47,25,90,89,38,68,
  9. 21]
复制代码
但是以上代码有个问题,random.choices是对一个序列进行重复采样,得到的数组存在重复数据,那如果不希望存在重复数据,而是希望进行无重复采样,怎么办?

可以用random.sample函数,示例代码:
  1. data=random.sample(data,k=100)
  2. print(data)
  3. [49,28,56,28,44,62,81,25,48,33,54,38,30,16,13,19,23,56,60,66,41,24,68,68,
  4. 77,92,78,24,66,3,80,94,78,41,84,88,21,56,25,25,75,24,38,82,31,52,23,10,
  5. 71,40,27,46,33,35,56,51,1,23,12,25,89,16,21,21,11,42,47,44,81,35,86,88,
  6. 29,36,77,16,39,6,57,69,96,68,24,86,97,90,69,10,68,98,56,44,83,47,70,17,
  7. 47,82,60,45]
复制代码
这样就可以得到无重复采样数据了。


[h1]三、如何实现排序算法[/h1]
算法种类较多,就不一一举例;再次就以希尔排序(Shell Sort)为例讲讲:

尔排序的原理:希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。


基础的插入法排序是两重循环,希尔排序是三重循环,最外面一重循环,控制增量gap,并逐步减少gap的值。二重循环从下标为gap的元素开始比较,依次逐个跨组处理。最后一重循环是对组内的元素进行插入法排序。这样进行排序的优点在于每次循环,整个序列的元素都将小元素的值逐步向前移动,数值比较大的值向后移动。
示例代码:
  1. fromdataimportDataSeq
  2. defShellSort(ds):
  3. assertisinstance(ds,DataSeq),"TypeError"
  4. Length=ds.length
  5. D=Length//2
  6. whileD>0:
  7. i=0
  8. whilei=1andds.data[j-D]>tmp:
  9. ds.SetVal(j,ds.data[j-D])
  10. j-=D
  11. ds.SetVal(j,tmp)
  12. i+=D
  13. D//=2
  14. if__name__=="__main__":
  15. ds=DataSeq(64)
  16. ds.Visualize()
  17. ds.StartTimer()
  18. ShellSort(ds)
  19. ds.StopTimer()
  20. ds.SetTimeInterval(0)
  21. ds.Visualize()
复制代码

[h1]四、如何把数组可视化出来[/h1]
有了随机数组初始化方法,再实现好排序函数,我们还差一步,就是把排序函数中每次移动数组后将数组可视化并输出。

对数组进行可视化,很容易想到python的可视化工具matplotlib!但是在项目中我并没有用matplotlib,而是用了numpy+opencv。

为什么不用matplotlib?

因为在排序过程中,每次修改数组,都希望能够实时修改图片并输出,matplotlib确实很方便,但是matplotlib的效率实在是不高,而且每次修改数组前后的两幅图片其实是差不多的。如果用matplotlib,每次都是要重新绘制图片,非常耗时!!!

所以考虑自己生成图片,在每次修改数组后,只将图片中改动的那两列进行修改即可!这样就比用matplotlib每次重新绘制图片效率高得多!

数组中主要有两种操作,一种是对某个idx赋值,一种是交换某两个idx的值。

示例代码:
  1. classDataSeq:
  2. WHITE=(255,255,255)
  3. RED=(0,0,255)
  4. BLACK=(0,0,0)
  5. YELLOW=(0,127,255)
  6. def__init__(self,Length,time_interval=1,sort_title="Figure",repeatition=False):
  7. pass
  8. defGetfigure(self):
  9. _bar_width=5
  10. figure=np.full((self.length*_bar_width,self.length*_bar_width,3),255,dtype=np.uint8)
  11. foriinrange(self.length):
  12. val=self.data[i]
  13. figure[-1-val*_bar_width:,i*_bar_width:i*_bar_width+_bar_width]=self.GetColor(val,self.length)
  14. self._bar_width=_bar_width
  15. self.figure=figure
  16. def_set_figure(self,idx,val):
  17. min_col=idx*self._bar_width
  18. max_col=min_col+self._bar_width
  19. min_row=-1-val*self._bar_width
  20. self.figure[:,min_col:max_col]=self.WHITE
  21. self.figure[min_row:,min_col:max_col]=self.GetColor(val,self.length)
  22. defSetVal(self,idx,val):
  23. self.data[idx]=val
  24. self._set_figure(idx,val)
  25. self.Visualize((idx,))
  26. defSwap(self,idx1,idx2):
  27. self.data[idx1],self.data[idx2]=self.data[idx2],self.data[idx1]
  28. self._set_figure(idx1,self.data[idx1])
  29. self._set_figure(idx2,self.data[idx2])
  30. self.Visualize((idx1,idx2))
复制代码

详细代码见github:
https://github.com/ZQPei/Sorting_Visualization
(就等你的小小star)其他的都没有什么了,有细节的问题可以在我的github下面留言勾搭。


最后附上一张效果图:




【本文作者】


丁彦军:一名痴恋于 Python 的码农,个人公号:「恋习Python」,在这里我们一起用Python 做些有意义的事。


推荐阅读
(点击标题可跳转阅读)
5 种使用 Python 代码轻松实现数据可视化的方法
Python 数据可视化 - 00 后高考大军
Python 数据可视化利器


觉得本文对你有帮助?请分享给更多人
关注「Python开发者」加星标,提升Python技能

喜欢就点一下「好看」呗~
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:835
帖子:167
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP