文章目录

  • 一、Python基础回顾
  • 定义类
  • 继承
  • 算法分析
  • 异序词检测示例

一、Python基础回顾

定义类

定义新类的做法是:提供一个类名以及一整套与函数定义语法类似的方法定义。所有的类都应该先提供构造方法,构造方法定义了数据对象的创建方式。self是一个总是指向对象本身的特助参数,它必须是第一个形式参数,但是在调用方法时,不需要提供相应的实际参数。要创建实例必须调用构造方法,使用类名并传入状态的实际值就能完成调用。
python为所有的类都提供了一套标准的方法,其中之一就是将对象转换成字符串的方法__str__。默认实现是返回实例的地址字符串。重新定义该方法的行为。

from fractions import gcd
class Fraction:
    def __init__(self,top,bottom):
        self.num = top
        self.den = bottom
    def show(self):
        print(self.num,"/",self.den)
    def __str__(self):
        return str(self.num)+"/"+str(self.den)
        # 化为最简 寻找分子和分母的最大公因数,然后将分子和分母除以最大公因数,结果就是最简分数
        # 重写add方法
    def __add__(self,otherfraction):
        newnum = self.num * otherfraction.den + self.den*otherfraction.num
        newden = self.den*otherfraction.den
        # 化简结果
        common = gcd(newnum,newden)
        return Fraction(newnum//common,newden//common)
    # 当两个对象指向同一个引用时,f1==f2,称为浅相等
    #  重写__eq__方法,建立深相等,根据值来判断而不是根据对象的引用
    def __eq__(self,other):
        firstnum = self.num * other.den
        secondnum = other.num * self.den
        return firstnum == secondnum
def gcd(m, n):
    # 欧几里得算法:如果m能被n整除,最大公因数就是n,否则,n与m除以n的余数才是子u大公因数
    # 分母必须为正
    while m % n != 0:
        oldm = m
        oldn = n
        m = oldn
        n = oldm % oldn
    return n

myfraction = Fraction(3,5)
# myfraction.show()
print(myfraction)
# 可以重写Fraction类中的很多其他方法,最重要的一些是基本的数学运算
f1 = Fraction(1,4)
f2 = Fraction(1,2)
f3 = f1+f2
print(f3)

运行结果:
3/5
3/4

继承

python中的子类可以从父类中集成特征数据和行为,父类也称为超类。

python定义结构体与类 python中数据类的结构体定义_数据结构


构建模拟程序用于模拟数字电路,逻辑门是这个模拟程序的基本构造的单元,它们代表其输入和输出之间的布尔代数关系,一般来说,逻辑门都有单一的输出,输出值取决于提供的输入值。

通过不同的模式将这些逻辑门组合起来并提供一系列输入值,可以构建具有逻辑功能的电路。为实现电路,首先需要构建逻辑门的表示,可以轻松的将逻辑门组织成类的继承层次结构。

python定义结构体与类 python中数据类的结构体定义_字符串_02


Connector类并不在逻辑门的继承层次结构中,但是他会使用该结构,从而使每一个连接器的两端都有一个逻辑门,这称为HAS-A关系。Connector与LogicGate是HAS-A关系。这意味着链接器内部包含LogicGate类的实例,但是不在继承层次结构中。在涉及类时,区分IS-A关系(需要继承)和HAS-A(不需要继承)非常重要。

但是在BinaryGate类中,逻辑门有两个输入,但连接器必须只连接其中一个,如果两个都能连接,那么默认选择PinA。如果PinA已经有了连接,就选择PinB。如果两个输入都已有连接,则无法连接逻辑门。现在的输入来源有两个:外部以及上一个逻辑门的输出。对方法getPinA和getPinB进行修改,如果输入没有与任何逻辑门相互连接,就和之前一样要求用户进行输入,如果有了连接就访问fromgate的输出值。这会出发fromgate处理逻辑。这个过程会已知持续,知道获取所有输入并且最终的输出值称为正在查询的逻辑门的输入。在某种意义上,这个电路反向工作,以获得所需的输入,在计算最后的结果。

python定义结构体与类 python中数据类的结构体定义_python_03

class LogicGate:
    # 每一个逻辑门都有一个用于识别的标签以及一个输出
    # 所有的逻辑门还需要能够知道自己的输出值,需要知道自己对应的逻辑运算是什么
    def __init__(self, n):
        self.label = n
        self.output = None

    def getLabel(self):
        return self.label

    def getOutput(self):
    #参数self指向实际调用方法的逻辑门对象的引用
        self.output = self.performGateLogic()
        return self.output


# 我们依据输入的个数来对逻辑门进行分类
class BinaryGate(LogicGate):
    # 唯一的行为是取得两个输入的值,由于这些值来自于外部 因此通过一条输入语句来要求用户提供
    def __init__(self, n):
        super().__init__(n) 
        # 两个输入
        self.pinA = None
        self.pinB = None
'''
对方法getPinA和getPinB进行修改,如果输入没有与任何逻辑门相互连接,就和之前一样要求用户进行输入,如果有了连接就访问fromgate的输出值。这会出发fromgate处理逻辑
'''
    def getPinA(self):
        if self.pinA == None:
            return int(input("enter pin A input for gate" + self.getLabel() + "-->"))
        else:
            return self.pinA.getFrom().getOutput()

    # def getPinB(self):
    #     return int(input("enter pin B input for gate" + self.getLabel() + "-->"))
    def getPinB(self):
        if self.pinB == None:
            return int(input("Enter Pin B input for gate "+self.getLabel()+"-->"))
        else:
            return self.pinB.getFrom().getOutput()
    # 使得每个togate都能选择适当的输入
    def setNextPin(self,source):
        if self.pinA == None:
            self.pinA = source
        else:
            if self.pinB == None:
                self.pinB = source
            else:
                print("Cannot Connect: NO EMPTY PINS on this gate")

class UnaryGate(LogicGate):
    def __init__(self, n):
        super().__init__(n)
        self.pin = None

    # def getPin(self):
    #     return int(input("enter pin  input for gate" + self.getLabel() + "-->"))

    def getPin(self):
        if self.pin == None:
            return int(input("Enter Pin input for gate "+self.getLabel()+"-->"))
        else:
            return self.pin.getFrom().getOutput()

    def setNextPin(self,source):
        if self.pin == None:
            self.pin = source
        else:
            print("Cannot Connect: NO EMPTY PINS on this gate")

class AndGate(BinaryGate):
    def __init__(self, n):
        super().__init__(n)

    def performGateLogic(self):
        a = self.getPinA()
        b = self.getPinB()
        if a == 1 and b == 1:
            return 1
        else:
            return 0


class OrGate(BinaryGate):
    def __init__(self, n):
        super().__init__(n)

    def performGateLogic(self):
        a = self.getPinA()
        b = self.getPinB()
        if a == 1 or b == 1:
            return 1
        else:
            return 0


class NotGate(UnaryGate):

    def __init__(self,n):
        UnaryGate.__init__(self,n)

    def performGateLogic(self):
        if self.getPin():
            return 0
        else:
            return 1

# 连接器类
'''
每一个连接器对象都包含一个fromgate和togate两个逻辑门实例,数值会从一个逻辑门的输出流向下一个逻辑门的输入 
对setNextPin的调用对于建立连接来说非常重要
需要将这个方法添加到逻辑门类中,以使每一个togate能够选择适当的输入
'''
class Connector:
    def __init__(self,fgate,tgate):
         # 连接来源
        self.fromgate = fgate
        # 连接去向
        self.togate = tgate

        tgate.setNextPin(self)

    def getFrom(self):
        return self.fromgate
    def getTo(self):
        return self.togate

# 创建实例对逻规则进行验证
def main1():
    g1 = AndGate("G1")
    print(g1.getOutput())

# 构造上图中的电路
def main2():
    g1 = AndGate("G1")
    g2 = AndGate("G2")
    g3 = OrGate("G3")
    g4 = NotGate("G4")
    c1 = Connector(g1, g3)
    c2 = Connector(g2, g3)
    c3 = Connector(g3, g4)
    print(g4.getOutput())
    
main1()
main2()

运行结果:
enter pin A input for gateG1-->1
Enter Pin B input for gate G1-->0
0
enter pin A input for gateG1-->1
Enter Pin B input for gate G1-->1
enter pin A input for gateG2-->1
Enter Pin B input for gate G2-->1
0

算法分析

算法和程序是不同的,算法是为逐步解决问题而涉及的一系列通用指令,程序是用某种变成语言对算法编码,同一个算法可以对应许多程序

算法分析关心的是基于所使用的计算资源比较算法,解决问题时要占用的空间或内存,或者根据算法窒执行所需要的时间进行比较和分析,这个指标有时称作算法的执行时间或运行时间。time中有一个time函数,她会以秒为单位返回自指定时间点起到当前的系统时钟时间,在首位调用一次这个函数计算差值,就可以得到以秒为单位执行的时间。

python定义结构体与类 python中数据类的结构体定义_python_04


python定义结构体与类 python中数据类的结构体定义_算法分析_05

异序词检测示例

如果一个字符串只是重排了另一个字符串的字符,例如heart,earth
假设要检查的两个字符串长度相同,并且都是由26个英文字母的小写形似组成的,我们的目标时编写一个布尔函数,它接受两个字符串,并能判断它们是否是异序词。

'''
清点法:
清点第一个字符串中的字符是否都出现在第2个字符中
清点是通过使用python中的特殊值None取代字符来实现的
python中字符串中的字符是不可修改的,先转换成列表
'''
def anagramSolution1(s1,s2):
    alist = list(s2)
    pos1 = 0
    stillOK = True

    while pos1 <len(alist) and stillOK:
        pos2 = 0
        found = False
        while pos2 <len(alist) and not found:
            if s1[pos1] == alist[pos2]:
                found = True
            else:
                pos2 = pos2 + 1
        if found:
            alist[pos2] =None
        else:
            stillOK = False
        pos1 = pos1 + 1
    return stillOK

分析算法:对于s1中的n个字符,检查每一个时都要遍历s2中的n个字符。要匹配s1中的一个字符,列表中的n个位置都要被访问一次。因此访问次数就变成1到n的整数之和。

python定义结构体与类 python中数据类的结构体定义_字符串_06


所以该方案的时间复杂度是O(n*n)

'''
尽管s1和s2是不同的字符串,但是只要是由相同的字符构成,它们就是异序词
按照字母表顺序个字符排序,异序词得到的结果将是同一个字符串
'''
def anagramSolution2(s1,s2):
    alist = list(s1)
    blist = list(s2)

    alist.sort()
    blist.sort()

    pos = 0
    matches = True
    while pos<len(s1) and matches:
        if alist[pos] == blist[pos]:
            pos = pos +1
        else:
            matches = False
    return matches

算法分析:在排序之后只需要遍历一次就可以比较n个字符,但是调用两次sort()是有代价的。

'''
计数法:
两个异序词具有相同数目的的字符
判断每个字符出现的次数,两个计数器列表相同,则这两个列表是异序词
'''
def anagramSolution3(s1,s2):
    c1 = [0]*26
    c2 = [0]*26

    for i in range(len(s1)):
        pos = ord(s1[i]) - ord('a')
        c1[pos] = c1[pos] + 1
    for i in range(len(s2)):
        pos = ord(s2[i]) - ord('a')
        c2[pos] = c2[pos]+1
    j=1
    stillOK = True
    while j<26 and stillOK:
        if c1[j] == c2[j]:
            j = j+1
        else:
            stillOK = False
    return stillOK

算法分析:这个方案也有循环,但是这个循环没有嵌套,前两个计数循环都是n阶,第三个循环只有26次,这是异序词检测的线性阶算法,尽管这个方法是线性的,但是它需要用额外的空间来存储计数器,这个算法用空间来换时间。

python定义结构体与类 python中数据类的结构体定义_数据结构_07


python定义结构体与类 python中数据类的结构体定义_算法分析_08