zoukankan      html  css  js  c++  java
  • 策略模式

     策略模式

     

    一、概述

          策略模式:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。也称为政策模式(Policy)。(Definea family of algorithms,encapsulate each one, andmake them interchangeable. Strategy lets the algorithmvary independently from clients that use it. 

    (策略模式把对象本身和运算规则区分开来,其功能非常强大,因为这个设计模式本身的核心思想就是面向对象编程的多形性的思想。)

          策略模式使用的就是面向对象的继承多态机制。

        策略模式适合使用在: 1. 多个类只有在算法或行为上稍有不同的场景。 2. 算法需要自由切换的场景。 3. 需要屏蔽算法规则的场景。

         使用策略模式当然也有需要注意的地方,那么就是策略类不要太多,如果一个策略家族的具体策略数量超过4个,则需要考虑混合模式,解决策略类膨胀和对外暴露问题。在实际项目中,我们一般通过工厂方法模式来实现策略类的声明。

    二、在OC中的实现

    以下内容来源于wnnvv的博客

         加入去超市购物,付款的方式有很多种:现金支付、银行卡支付、信用卡支付等等。

    1、创建一个父类

    @interface Strategy : NSObject
    - (void)pay;
    @end

    2、创建一个现金支付类,继承strategy,重写pay方法

    复制代码
    @interface payCash : Strategy
    @end
    @implementation payCash
    - (void)pay
    {
        NSLog(@"使用现金支付");
    }
    @end
    复制代码

    3、创建一个银行卡支付类,同上

    复制代码
    @interface payCard : Strategy
    @end
    @implementation payCard
    - (void)pay
    {
        NSLog(@"使用银行卡支付");
    }
    @end
    复制代码

    4、创建组织类,用于将各个方法类组织在一起

    复制代码
    @implementation Context
    + (void)contextToUse:(id)strategy
    {
        Strategy *st = strategy;
        [st pay];
    }
    @end
    复制代码

    5、使用,将具体的使用方法传入context

    [Context contextToUse: [[payCash alloc]init]]; 

    6、总结:策略模式将功能相同或者相似的具体策略从功能大类中分离开,再组织起来,降低耦合性,每个具体类的修改都不会影响其他类。 


    参考文章:

    一、hguisu   设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 

     

    排序算法学习,python实现

     

    原创博文,转载请注明出处

    利用周六周末的时间把几种基本的排序方法用python实现了一下,废话少说,直接上代码。

    本文不注重基础知识的讲解,只做大致的描述,大家如果不清楚概念,自行查找资料。

    直接插入排序:

      每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。

    复制代码
     1 def insert(arr):
     2     l = len(arr)
     3     for i in range(1,l):
     4         if arr[i]<arr[i-1]:
     5             temp =arr[i]
     6             j=i-1
     7             arr[j+1]=arr[j]
     8             j=j-1
     9             while j>=0 and arr[j]>temp:
    10                 arr[j+1]=arr[j] #元素后移
    11                 j=j-1
    12             arr[j+1]=temp
    13     return arr
    14 arra=[98,36,-9,0,47,23,1,8,10,7]
    15 print insert(arra)
    复制代码

    折半插入排序:

      折半插入排序就是就是将上面直接插入排序中查找有序子表的工作使用折半查找来实现,在确定出待插入位置后,就可以统一的向后移动元素。

    复制代码
     1 # -*- coding: cp936 -*-
     2 def find_ff(arr,x):#折半查找
     3     size =len(arr)
     4     low = 0
     5     high = size-1
     6     while low<=high:
     7         mid =(low+high)/2
     8         if arr[low]==x:
     9             return low
    10         elif arr[high]==x:
    11             return high
    12         elif arr[mid]==x:
    13             return mid
    14         elif arr[mid] > x:
    15             high = mid-1
    16         else:
    17             low = mid+1
    18             
    19 def insert_ff(arr):#升序
    20     l = len(arr)
    21     for i in range(1,l):
    22         if arr[i]<arr[i-1]:
    23             temp =arr[i]
    24             j=i-1
    25             low = 0
    26             high = j
    27             while low<=high:
    28                 mid = (low+high)/2
    29                 print 'mid',mid
    30                 if arr[mid] > temp:
    31                     high = mid-1
    32                 else:
    33                     low = mid+1
    34             print 'high+1',high+1
    35             print 'j',j
    36             if j==0:
    37                 arr[j+1],arr[j]=arr[j],arr[j+1]
    38             else:
    39                 print 'action 2 '
    40                 for x in range(j,high,-1):#移动元素
    41                     print 'x',x
    42                     arr[x+1]=arr[x]
    43                 arr[high+1]=temp
    44         print arr
    45     return arr
    46 
    47 arra=[98,36,-9,0,47,23,1,8,10,7]
    48 print insert_ff(arra)    
    复制代码

    在分析折半插入排序时 一定要搞清楚元素的索引值。所以我在里面加入了print语句是为了测试而加入的 ,可以忽略。

    希尔排序 

    复制代码
     1 def shell(arr):
     2     l = len(arr)
     3     h = l/2
     4     while h>=1:
     5         for i in range(l):
     6             j = i
     7             while j>=h and arr[j]<arr[j-h]:
     8                 arr[j],arr[j-h]=arr[j-h],arr[j]
     9         h=h/2 
    10     return arr
    11 arra=[98,36,-9,0,47,23,1,8,10,7]
    12 print shell(arra)
    复制代码

     交换排序 : 冒泡排序和快速排序 

       冒泡排序比较简单 

    复制代码
    # -*- coding: cp936 -*-
    def bubble(arr):#降序
        size = len(arr)
        for i in range(size-1):
            for j in range(i,size-1):
                if arr[j+1]>arr[j]:
                    arr[j+1],arr[j]=arr[j],arr[j+1]
    
        return arr
    
    arra=[98,36,-9,0,47,23,1,8,10,7]
    print bubble(arra)
    复制代码

    快速排序 :对冒泡排序的一种改进,基本思想是基于分治的

    复制代码
     1 # -*- coding: cp936 -*-
     2 def partition(data,low,high):
     3     if low<high:
     4         x = data[low]#以第一个元素作为枢轴值 
     5         while low<high: #循环跳出条件 
     6             while low<high and data[high]>=x:
     7                 high -= 1
     8             data[low]=data[high]#将小于枢轴值得元素移到左端
     9             while low<high and data[low]<=x:
    10                 low += 1
    11                 print low
    12             data[high]=data[low]#将大于枢轴值的元素移到右端
    13         data[low]=x
    14     return low
    15 def quick(arr,low,high):
    16     if low < high:
    17         pivotop = partition(arr,low,high)
    18         quick(arr,low,pivotop-1)
    19         quick(arr,pivotop+1,high)
    20     return arr
    21 
    22 arra=[98,36,-9,0,47,23,1,8,10,7]
    23 print quick(arra,0,len(arra)-1)
    复制代码

    在这儿我们举了一个特例,就是第一个元素大于后面的所有元素,在测试过程中发现了好多问题,比如第六行和第九行再次加入了low<high的判断条件是为了避免边界条件问题,边界条件作为测试过程的重要环节,由于逻辑性较强,所以比较困难调试。

    选择排序 :简单排序和堆排序

    简单排序比较简单实现如下

    复制代码
    def simple(arr):
        size = len(arr)
        for i in range(size):
            mini = arr[i]
            for j in range(i,size):
                if arr[j] < mini:
                    mini = arr[j]
                    arr[i],arr[j]=arr[j],arr[i]
        return arr
    arra=[98,36,-9,0,47,23,1,8,10,7]
    print simple(arra)
    复制代码

    堆排序:与简单排序不同,在排序过程中,将L[1...n]看成是一棵完全二叉树的顺序存储结构,利用二叉树中双亲节点和孩子结点的内在关系(搞清楚各种二叉树的区别),在当前无序区选择关键字最大或最小的元素。

          堆的定义:n个关键字序列L[1...n]成为堆,当且仅当满足下列条件之一:

                     1. L(i)<=L(2i),且L(i)<=L(2i+1) 称为小根堆,也就是满足双亲节点小于孩子节点

                     2. L(i)>=L(2i),且L(i)>=L(2i+1) 称为大根堆,也就是满足双亲节点大于孩子节点

         堆排序的关键是构建初始栈,n个结点的完全二叉树,最后一个结点是第n/2个结点的孩子。对第n/2个结点为根的子树筛选,使该子树成为堆。之后向前依次对各结点为根的子树进行筛选(对于大根堆:若根结点的关键值小于孩子结点中关键值较大者,则交换)。

     堆排序这儿还是遇到了不少麻烦,一定要理清脉络。有一点需要注意,一定要考虑到只有左孩子没有右孩子的情况,网上好多版本都没有考虑到这一特殊情况,因为加入没有右孩子结点你再载入值得话就会触发异常IndexError: list index out of range。

    复制代码
     1 # -*- coding: cp936 -*-
     2 def buildHeap(arr):
     3     size = len(arr)
     4     for i in range(getParent(size-1),-1,-1):
     5         adjustDown(arr,size-1,i) #注意 size-1不是size
     6 
     7 def getParent(k):
     8     if k%2==1:
     9         return int(k/2)
    10     else:
    11         return k/2-1
    12 
    13 def adjustDown(arr,size,k):#一定要注意size的值
    14     print 'k',k 
    15     left = 2*k+1
    16     right = left+1
    17     maxp = k
    18     if left<size and arr[k]<arr[left]:#先判断左孩子
    19         maxp = left
    20     if left<size and right<size:#假如有右孩子,取两个孩子结点的最大值
    21         maxlr = left if arr[left]>arr[right] else right
    22     if left<size and right<size and arr[k]<arr[maxlr]:
    23         maxp = maxlr
    24     if maxp!=k:
    25         arr[maxp],arr[k]=arr[k],arr[maxp]
    26         print arr
    27         adjustDown(arr,size,maxp)
    28 
    29 def heap(arr):
    30     size = len(arr)
    31     buildHeap(arr)
    32     print 'build',arr
    33     for i in range(size-1,-1,-1):#size-1
    34         arr[i],arr[0]=arr[0],arr[i]
    35         print arr[i],arr[0]
    36         adjustDown(arr,i,0)
    37     return arr
    38 
    39 arra=[98,36,-9,47,23,1,8]
    40 print heap(arra)
    复制代码

    归并排序:

      归并的含义是将两个或两个以上的有序表组合成一个新的有序表。最常见的是2-路归并排序。在程序设计中merge()是把两个有序表合并的操作。递归形式的2-路归并排序算法是基于分治的,其过程如下: 

          分解:将含有n个元素的待排序表分成各含n/2个元素的子表,采用 2-路归并排序算法对两个子表递归的进行排序 

          合并:合并两个已排序的子表得到排序结果。

           性能分析: 空间复杂度为 O(n),每一趟归并的时间的复杂度为O(n),共需要进行log2n趟归并,所以算法的时间复杂度为 O(nlog2n)。 merge()操作并不会改变相同关键字记录的相对次序,故算法稳定。

    复制代码
     1 def mergeSort(arr):
     2     if len(arr)<=1:
     3         return arr
     4     mid = len(arr)/2
     5     left=mergeSort(arr[:mid])
     6     right=mergeSort(arr[mid:])
     7     return merge(left,right)
     8 
     9 def merge(left,right):
    10     result=[]
    11     i,j=0,0
    12     while len(left)>i and len(right)>j:
    13         if left[i]<=right[j]:
    14             result.append(left[i])
    15             i+=1
    16         else:
    17             result.append(right[j])
    18             j+=1
    19     result +=left[i:]
    20     result +=right[j:]
    21     return result
    22 
    23 arra=[98,36,-9,0,47,23,1,8,10,7]
    24 print mergeSort(arra)
    复制代码

    基数排序:

         园内 有一篇讲解基数排序的,http://www.cnblogs.com/Braveliu/archive/2013/01/21/2870201.html,图文并茂,很不错,具体概念就不讲解了。这儿我就用python实现一下吧。

    复制代码
     1 # -*- coding: cp936 -*-
     2 def radixSort_LSD(arr,d):
     3     for i in xrange(d):
     4         S = [[] for j in xrange(10)]
     5         for x in arr:
     6             S[x/(10**i)%10].append(x)
     7         arr = [x for y in S for x in y]
     8     return arr
     9 
    10 def radixSort_MSD(arr,d):
    11     r = int(d-1)
    12     if r>=0:
    13         S = [[] for j in xrange(10)]
    14         L =[]
    15         for x in arr:
    16             S[x/(10**r)%10].append(x)
    17         for y in S:
    18             M=radixSort_MSD(y,r)
    19             L.append(M)   
    20         arr = [x for y in L for x in y]
    21     return arr
    22 
    23 arra=[98,36,9,0,47,23,1,8,10,7]
    24 print radixSort_MSD(arra,2)
    25 print radixSort_LSD(arra,2)
    复制代码

    注意MSD和LSD的区别,

    LSD的排序方式由数值的最右边(低位)开始,而MSD则相反,由数值的最左边(高位)开始。

    注意一点:LSD的基数排序适用于位数少的数列,如果位数多的话,使用MSD的效率会比较好。

    MSD的方式与LSD相反,是由高位数为基底开始进行分配,但在分配之后并不马上合并回一个数组中,而是在每个“桶子”中建立“子桶”,将每个桶子中的数值按照下一数位的值分配到“子桶”中。所以在MSD中我构建了一个L作为子桶。 有没有感觉python非常优雅,简简单单的几句代码就解决了问题。

    计数排序: 

      计数排序一般应用于序列元素是正整数的时候,计数排序不是比较排序,排序的速度快于任何比较排序算法。在学习计数排序的时候还是费了很大功夫,一直搞不懂其中的道理。

    复制代码
     1 # -*- coding: cp936 -*-
     2 def countSort(arr):
     3     size = len(arr)
     4     mini = maxp = arr[0]
     5     for i in arr:#找出最大最小值
     6         if i<mini:
     7             mini = i
     8         if i>maxp:
     9             maxp = i
    10     bound = maxp - mini +1 
    11     count = [0 for i in range(bound)]
    12     sorted_arr = [0 for i in range(size)]
    13     for i in range(size):
    14         count[arr[i]-mini]+=1#arr的元素值个数对应count的元素值,
    15     x=0     
    16     for i in range(mini,maxp+1):
    17         for j in range(0,count[i-mini]):
    18             sorted_arr[x]=i
    19             x+=1
    20 
    21     return sorted_arr
    22 arra=[98,36,5,47,23,1,8]
    23 print countSort(arra)
    复制代码

     计数排序的时间复杂度为O(n),这是其他排序方法难以达到的(其他算法的时间复杂度要么为O(n2),要么为O(nlogn))。

     
     
    分类: 数据结构
     
  • 相关阅读:
    八爪鱼 爬取微博中的图片到本地
    【简易采集】美团数据抓取方法 八爪鱼
    jeesite 的提示消息图标
    SpringBoot 入门 Demo
    spring 简单入门实例
    正则表达式之匹配替换
    数据结构之堆栈
    c#设计模式之装饰者模式
    c#设计模式之策略模式
    一个自然数在1700和1800之间,且被5除余3,被7除余4,被11除余6,求符合条件的数
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3479410.html
Copyright © 2011-2022 走看看