图形图像算法中必须要了解的设计模式(2)

图形图像算法中必须要了解的设计模式(2)

AI越来越火热,人工智能已然成风!而人工智能最重要是各种算法,因此机器学习越来越受到追捧,算法越来越被重视。

作为一个算法的研究者,写出一手高级算法当然是令人兴奋的一件事!但你是否有时会有这种感觉:

  1. 写的算法很难通用于所有的数据类型!每来一个新类型的数据,又得改一下算法,或新加一个方法来支持这种类型。
  2. 有时候多个算法需要灵活组合,甚至每个算法的顺序不一样都会产生不一样的效果;每一种组合都要为其构建一个新算法,即累又麻烦。
  3. 算法越来越多,自建的算法库也越来越庞大而难于管理;

这个时候,让你的算法具有更好通用性、拓展性就显得极为重要!因此,你必须要掌握几个重要的设计模式来解决这些问题。今天介绍一种在算法领域中应用最广泛的设计模式——策略模式

策略模式

定义一系列算法,将每个算法都封装起来,并且使他们之间可以相互替换。策略模式使算法可以独立于使用它的用户而变化。

策略模式是对算法、规则的一种封装。它具有以下的优点:

  • 算法(规则)可自由地切换。
  • 避免使用多重条件判断。
  • 方便拓展和增加新的算法(规则)。

应用案例

假设有这样一个应用场景:

有一Person类,有年龄(age),体重(weight),身高(height)三个属性。现要对Person的一组对象进行排序,但并没有确定根据什么规则来排序,有时需要根据年龄进行排序,有时需要根据身高进行排序,有时可能是根据身高和体重的综合情况来排序,还有可能……

通过对这个应用场景进行分析,我们会发现,这里需要有多种排序算法,而且需要动态地在这几种算法中进行选择,在未来可能还会添加一新的排序规则……

怎样让我们的排序算法更加的灵活,以适应各种各样的排序规则呢?这里我们就要用到策略模式。来,我们一起看一下具体的代码实现吧。

源码示例:

class Person:
    "人类"

    def __init__(self, name, age, weight, height):
        self.name = name
        self.age = age
        self.weight = weight
        self.height = height

    def showMysef(self):
        print(self.name + " " + str(self.age) + " years old, " + str(self.weight) + "kg, " + str(self.height) + "m.")

class ICompare:
    "比较算法"

    def comparable(self, person1, person2):
        "person1 > person2 返回值>0,person1 == person2 返回0, person1 < person2 返回值小于0"
        pass


class CompareByAge(ICompare):
    "通过年龄排序"

    def comparable(self, person1, person2):
        return person1.age - person2.age

class CompareByHeight(ICompare):
    "通过身高进行排序"

    def comparable(self, person1, person2):
        return person1.height - person2.height

class SortPerson:
    "Person的排序类"

    def __init__(self, compare):
        self.__compare = compare

    def sort(self, personList):
        "排序算法,这里采用最简单的冒泡排序"
        n = len(personList)
        for i in range(0, n-1):
            for j in range(0, n-i-1):
                if(self.__compare.comparable(personList[j], personList[j+1]) > 0):
                    tmp = personList[j]
                    personList[j] = personList[j+1]
                    personList[j+1] = tmp
            j += 1
        i += 1

测试代码:

def testSortPerson():
    personList = [
        Person("Tony", 2, 54.5, 0.82),
        Person("Jack", 31, 74.5, 1.80),
        Person("Nick", 54, 44.5, 1.59),
        Person("Eric", 23, 62.0, 1.78),
        Person("Helen", 16, 45.7, 1.60)
    ]
    sorter0 = SortPerson(CompareByAge())
    sorter0.sort(personList)
    print("根据年龄进行排序后的结果:")
    for person in personList:
        person.showMysef()
    print()

    sorter1 = SortPerson(CompareByHeight())
    sorter1.sort(personList)
    print("根据身高进行排序后的结果:")
    for person in personList:
        person.showMysef()

输出结果:

根据年龄进行排序后的结果:
Tony 2 years old, 54.5kg, 0.82m.
Helen 16 years old, 45.7kg, 1.6m.
Eric 23 years old, 62.0kg, 1.78m.
Jack 31 years old, 74.5kg, 1.8m.
Nick 54 years old, 44.5kg, 1.59m.

根据身高进行排序后的结果:
Tony 2 years old, 54.5kg, 0.82m.
Nick 54 years old, 44.5kg, 1.59m.
Helen 16 years old, 45.7kg, 1.6m.
Eric 23 years old, 62.0kg, 1.78m.
Jack 31 years old, 74.5kg, 1.8m.

看到这,一些熟悉Python的同学肯定要吐槽了!Python是一个简洁明了的语言,使用十几行代码就能解决的问题(如下面的实现代码),为什么要写上面这一大堆的东西。

from operator import itemgetter,attrgetter
def testPersonListInPython():
    "用Python的方式对Person进行排序"

    personList = [
        Person("Tony", 2, 54.5, 0.82),
        Person("Jack", 31, 74.5, 1.80),
        Person("Nick", 54, 44.5, 1.59),
        Person("Eric", 23, 62.0, 1.78),
        Person("Helen", 16, 45.7, 1.60)
    ]

    # 使用使用operator模块根据年龄进行排序
    print("根据年龄进行排序后的结果:")
    sortedPerons = sorted(personList, key = attrgetter('age'))
    for person in sortedPerons:
        person.showMysef()
    print()

    print("根据身高进行排序后的结果:")
    sortedPerons1 = sorted(personList, key=attrgetter('height'))
    for person in sortedPerons1:
        person.showMysef()

输出的结果和上面是一模一样的,这里不再赘述。

能提出这个问题,说明你一定是带着思考在阅读!之所以还要这么写,出于以下几个原因:

  1. 设计模式是一种编译思想,他和语言没有强关联,应当适用于所有面向对象的语言。Python因为语言本身的灵活性和良好的封装性,使得其自带了很多的功能,而其他语言并没有这样的功能。也许你的算法就是用C++或者Java来写的呢!为了让熟悉其他语言的人也能看懂,这里使用了最接近面向对象思维的方式进行实现(即使你熟悉Python也可通过他来学习一种新的思维方式)。
  2. 使用Python语言本身的特性,还是难以实现一些特殊的需求,如要根据身高和体重的综合情况来排序(身高和体重的权重分别是0.6和0.4)。用策略模式就可以很方便地实现,只需要增加一个CompareByHeightAndWeight的策略类就可以,如下面代码:
class CompareByHeightAndWeight(ICompare):
    "根据身高和体重的综合情况来排序(身高和体重的权重分别是0.6和0.4)"

    def comparable(self, person1, person2):
        value1 = person1.height * 0.6 + person1.weight * 0.4
        value2 = person2.height * 0.6 + person2.weight * 0.4
        return value1 - value2

使用策略模式能让我们写的算法适用于各种规则和各种对象类型,极大地提高了算法的灵活性和拓展性。

Get到技能点了吗?

原文发布于微信公众号 - OpenCV学堂(CVSCHOOL)

原文发表时间:2018-07-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员叨叨叨

8.2 函数重载

Cg 语言支持函数重载(Functon Overlaoding),其方式和 C++基本一致,通过形参列表的个数和类型来进行函数区分。例如:

1022
来自专栏我的python

递归方法的理解

递归思想算是编程中比较常见但对初学者而言又有些难以理解的方法了。在leetcode上刷了几道题都用递归思想成功解决后觉得应该贯彻互联网的开源共享精神,总结一下自...

930
来自专栏C语言及其他语言

初学C语言的学习计划

背景:很多同学在学习C语言的过程中,常常会遇到这样的问题,即“教材看完了,知识点也懂,但写不出来程序”,这段时间,我们通过长期与有多年C语言研究经验的教授、教师...

3554
来自专栏take time, save time

你所能用到的数据结构(二)

      周末开始更新了,首先感谢各位对我写的东西还能保持兴趣,先回答几个留言中的一个问题和我对无损编码那一节的一个留言的一个看法,第一个是推荐算法书,首先,...

3126
来自专栏牛客网

吉比特面试经验 游戏研发岗实习生

3320
来自专栏程序员互动联盟

【答疑解惑】失之毫厘谬以千里

1、scanf使用陷阱 ? ? 如果scanf中%d是连着写的如“%d%d”,在输入数据时,数据之间不可以加逗号,只能是空格或tab键或者回车键“1 2” 或 ...

2967
来自专栏阮一峰的网络日志

为什么Lisp语言如此先进?(译文)

上周,《黑客与画家》总算翻译完成,已经交给出版社了。 翻译完这本书,累得像生了一场大病。把书稿交出去的时候,心里空荡荡的,也不知道自己得到了什么,失去了什么。 ...

2896
来自专栏take time, save time

Think in 递归

     网上写递归的文章可以用汗牛充栋来形容了,大多数都非常清晰而又细致的角度上讲解了递归的概念,原理等等。以前学生的时候,递归可以说一直是我的某种死穴,原理...

40912
来自专栏海天一树

全国青少年信息学奥林匹克分区联赛(NOIP)竞赛大纲

* MS DOS与Windows的使用基础(在2013年后,很少出现与MS DOS相关内容)

1394
来自专栏SnailTyan

枚举——生理周期

1. 枚举 枚举是基于逐个尝试答案的一种问题求解策略。 2. 生理周期 问题描述 人有体力、情商、智商的高峰日子,它们分别每隔23天、28天和33天出现一次...

1990

扫码关注云+社区