基本算法Python实现

什么是计算机科学?
        ●首先明确的一点就是计算机科学不仅仅是对计算机的研究,虽然计算机在科学发展的过程中发挥了重大的作用,但是它只是一个工具,一个没有灵魂的工具而已。所谓的计算机科学实际上是对问题、解决问题以及解决问题的过程中产生产生的解决方案的研究。例如给定-个问题,计算机科学家的目标是开发-个算法来处理该问题,最终得到该问题的解、或者最优解。所以说计算机科学也可以被认为是对算法的研究。因此我们也可以感受到,所谓的算法就是对问题进行处理且求解的一种实现思路或者思想。

如何形象化的理解算法
        ●一个常胜将军在作战之前都会进行战略的制定,目的是为了能够在最短的时间切成本消耗最低的情况下获取最终的胜利。如果将编码作为战场,则程序员就是这场战役的指挥官,你如何可以将你的程序可以在最短且消耗资源最小的情况下获取最终的执行结果呢?算法就是我们的策略!

评判程序优劣的方法
        ●消耗计算机资源和执行效率(不推荐,无法直观)
        ●计算算法执行的耗时(适当推荐,因为会受机器和执行环境的影响)
        ●时间复杂度(推荐)

时间复杂度
        ●评判规则:量化算法执行的操作/执行步骤的数量
        ●最重要的项:时间复杂度表达式中最有意义的项
        ●大O记法:就是使用时间复杂度衡量算法好坏的表现形式。
                ■O(最重要的一项)
 

def sumOfN(n):
    theSum = 0 #1
    for i in range(1,n+1):
        theSum = theSum + i #n
    return theSum 办1
    print ( sumOfN(10))
# 时间复杂度 n+1+1 
# O(n)
a=5
b=6
c=10 
for i in range(n):
    for j in range(n) :
        x = i * i
        y = j * j
        z = i * j
for k in range(n):
    w=a*k+45
    v=b*b
d=33
# 时间复杂度 3 + 3n**2 + 2n + 1
# O(n**2)

●常见的时间复杂度:
        ■0(1)< O(\log_{2}n) < 0(n) < O(n\log_{2}n) < 0(n^2) < 0(n^3) < 0(2^n) < O(n) < o(n^n)

数据结构
        ●概念:对于数据(基本类型的数据(intg,float,char) )的组织方式就被称作为数据结构。数据结构解决的就是一组数据如何进行保存,保存形式是怎样的。

        ●使用不同的形式组织数据,在基于查询时的时间复杂度是不一样的。 因此认为算法是为了解决实际问题而设计的,数据结构是算法需要处理问题的载体。

 python结构性能分析

        ●实例化一个空列表,然后将0-n范围的数据添加到列表中。 (四种方式)
        ●timeit模块: 该模块可以用来测试一段python代码的执行速度/时长。
        ●Timer类: 该类是timeit模块中专门用于测量python代码的执行速度时长的。原型为: class
                timeit.Timer(stmt=' 'pass',setup='pass‘).
                ■stmt参数:表示即将进行测试的代码块语句。
                ■setup: 运行代码块语句时所需要的设置。
        ●timeit函数: timeit.Timer.timeit(number10000),.该函数返回代码块语句执行number次的平均耗时。

from timeit import Timer
def test01():
    alist=[]
    for i in range(1000):
        alist.append(i)
    return alist
def test02():
    alist=[]
    for i in range(1000):
        alist = alist + [i]
    return alist
def test03():
    alist = [i for i in range(1000)]
    return alist
def test04():
    alist=list(range(1000))
    return alist
if__name__ == '__main__':
    timer = Timer(stmt='test01()',setup='from __main__ import test01')

        ●特性:先进后出
        ●栈顶,栈底
                ■从栈顶向栈底添加元素,从栈顶取元素

        ●应用:每个web浏览器都有一个返回按钮。当你浏览网页时,这些网页被放置在一个栈中(实际是网页的网址) .你现在查看的网页在顶部,你第一个查看的网页在底部。如果按'返回'按钮,将按相反的顺序浏览刚才的页面。

        ●Stack()创建一个空的新栈。它不需要参数,并返回一个空栈。
        ●push(item)将一个新项添加到栈的顶部。 它需要item做参数并不返回任何内容。
        ●pop()从栈中删除顶部项。它不需要参数并返回item.栈被修改。
        ●peek()从栈返回顶部项,但不会删除它。不需要参数。不修改栈。
        ●isEmpty() 测试栈是否为空。不需要参数,并返回布尔值.
        ●size() 返回栈中的item数量。不需要参数,并返回一个整数。

class Stack():
    def __init__(self):#构建一个空栈
        self.items=[]
    def push(self,item):
        #从栈顶添加到栈底
        self.items.append(item)
    def pop(self):
        #从栈顶向栈底取元素
        return self.items.pop()
    def peek(self):#返回栈顶元囊下标
        return len(self.items)-1
    def isEmpty(self):
        return self.items == [ ]
    def size(self):
        return len(self.items)

 队列                                                                                                                                                        ●队列:先进先出
        ●应用场景:
                ■我们的计算机实验室有30台计算机与一台打印机联网。当学生想要打印时,他们的打印任务与正在等待的所有其他打印任务"一致"。第一个进入的任务是先完成。如果你是最后一-个,你必须等待你前面的所有其他任务打印

        ●Queue()创建- -个空的新队列。 它不需要参数,并返回-个空队列。
        ●enqueue(item) 将新项添加到队尾。它需要iterm作为参数,并不返回任何内容。
        ●dequeue() 从队首移除项。它不需要参数并返回item.队列被修改。
        ●isEmpty() 查看队列是否为空.它不需要参数,并返回布尔值.
        ●size() 返回队列中的项数。它不需要参数,并返回一个整数。

class Queue():
    def __init__(self):#构建一个空栈
        self.items=[]
    def enqueue(self,item):
        #从栈顶添加到栈底
        self.items.insert(0, item)
    def dequeue(self):
        #从栈顶向栈底取元素
        return self.items.pop()
    def isEmpty(self):
        return self.items == [ ]
    def size(self):
        return len(self.items)

双端队列
        ●同同列相比,有两个头部和尾部。可以在双端进行数据的插入和制除,提供了单数据结构中栈和队列的特性

        ●Deque0创建一个空的新deque.它不需要参数,并返回空的deque.
        ●addFront(tem) 将-一个新项添加到deque的首部。它需要item参数并不返回任何内容。
        ●addRearfitem) 将-个新项添加到deque的尾部。它需要item参数并不返回任何内容。
        ●removeFront() 从deque中删除首项。它不需要参数并返回item. deque 被修改。
        ●removeRear0 从deque中删除尾项。它不需要参数并返回item, deque 被修改。
        ●isEmpty0 测试deque是否为空.它不需要参数,并返回布尔值。
        ●size0 返回deque中的项数。它不需要参数,并返回-一个整数。

内存
        ●计算机的作用
                ■存储和运算二进制的数据。
        ●计算机如何实现1+1=?操作
                ■将1加载到计算机内存中,然后基于计算机的加法寄存器对指定内存中存储的数据进行加法运算。
        ●变量的概念.
                ■本质讲,变量指的就是计算机中的某-块内存空间。
                ■内存空间有两个固有的属性
                        。地址:使用16进制的数表示
                                。作用:方便cup寻址。门牌号。
                        。大小: bit,byte.kb,.mb.gb.tb
                                。决定该块内存存储的数值的范围

        ●理解a=10的内存图(引用,指向)
                ■引用:就是变量,通常将,变量表示的就是一-块内存空间的地址。
                ■指向:如果一个变量或者引用存储表示了某块内存空间的地址后,则该变量或引用指向了该块内存空间。
        ●不同数据占用内存空间的大小
                ■bit(位): 1bit只能存储- -位二进制的数。
                ■byte字节: 8bit.

        数组和列表的区别,对于列表来说由于地址开辟的空间不一样,导致不能顺序取数据,于是便产生了另外一个连续的空间作为存储地址的容器。         

         ●顺序表的弊端:顺序表的结构需要预先知道数据大小来申请连续的存储空间,而在进行扩充时又需要进行数据的搬迁。

        链表相对于顺序表,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理且进行扩充时不需要进行数据搬迁。
        ●链表(Linked list) 是- -种常见的基础数据结构,是一种线性表,但是不像顺序表- -样连续存储数据,而是每-个结点(数据存储单元)里存放下一个结点的信息(即地址)

        ● is_empty(): 链表是否为空
        ● length():链表长度
        ● travel(): 遍历整个链表
        ● add(item):链表头部添加元素
        ● append(item):链表尾部添加元素
        ● insert(pos, item):指定位置添加元素
        ● remove(item):删除节点
        ● search(item): 查找节点是否存在

# 节点的封装
class Node():
    def __init__(self,item):
        self.item = item
        self.next = None
#链表的封装
class Link():
    def __init__(self):#构建一个空链表
        # 这里是一个地址
        self._head = None
    # head永远要指向链表中的第一个节点,None表示链表中没有节点。
    def add(self, item):
        node = Node(item)
        node.next = self._head
        self._head = node  # 此处的node就是地址

    def travel(self):
        cur = self._head
        while cur:
            print(cur.item)
            cur = cur.next

    def isEmpty(self):
        return self._head == None

    def length(self):
        cur = self._head
        count = 0
        while cur:
            count += 1
            cur = cur.next
        return count

    def append(self, item):
        node = Node(item)
        # 如果链表为空
        if self._head == None:
            self.add(item)
            self._head = node
            return
        # 如果链表为非空
        pre = None  # pre是指向cur前面的一个节点
        cur = self._head
        while cur:
            pre = cur
            cur = cur.next
        pre.next = node
    # 查询item是否存在链表中
    def search(self, item):
        find = False
        cur = self._head
        while cur:
            if cur.item == item:
                find = True
                break
            else:
                cur = cur.next
        return find

    def insert(self, pos, item):
        node = Node(item)
        cur = self._head
        pre = None
        # 判断位置为0的情况
        if pos == 0:
            self._head = node
            node.next = cur
        for i in range(pos):
            pre = cur
            cur =cur.next
        pre.next = node
        node.next = cur
    def remove(self, item):
        pre = None
        cur = self._head
        if self._head.item == item:
            self._head = cur.next
            return
        while cur:
            pre = cur
            cur = cur.next
            if cur.item == item:
                pre.next = cur.next
                return
    def reverse(self):
        pre = self._head
        cur = pre.next
        next_node = cur.next
        pre.next = None
        while True:
            cur.next = pre
            #依次将pre,next,next_node 向后偏移
            pre = cur
            cur = next_node
            if next_node != None:
                next_node = next_node.next
            else:
                break
        self._head = pre

二叉树
        ●根节点:树中上部的节点
        ●左叶子节点
        ●右叶子节点
        ●子树
                ■完整的子树
                        。一个根节点,左右叶子节点组成
                ■不完整的子树
                        。根节点,左叶子节点
                        。根节点,右叶子节点
                        。根节点
                        。特点:每一个节点都可以作为某- -颗子树的根节点

class Node():
    def __init__(self, item):
        self.item = item
        self.left = None  # 指向该节点的左叶子节点
        self.right = None  # 指向该节点的右叶子节点
class Tree():
    def __init__(self):
        self.root = None # 永远指向二叉树中的根节点
    # 自上到下,从左到右的插入
    def insert(self, item):
        node = Node(item)
        # 如果树为空
        if self.root == None:
            self.root = node
            return
        # 如果不为空
        cur = self.root
        q = [cur]
        while True:
            n = q.pop(0)
            if n.left != None:
                q.append(n.left)
            else:
                n.left = node
                break
            if n.right != None:
                q.append(n.right)
            else:
                n.right = node
                break

    def travel(self):
        cur = self.root
        q = [cur]
        while q:
            n = q.pop(0)
            print(n.item)
            if n.left != None:
                q.append(n.left)
            if n.right != None:
                q.append(n.right)
    def forward(self, root):
        if root == None:
            return
        print(root.item)
        self.forward(root.left)
        self.forward(root.right)
    def middle(self, root):
        if root == None:
            return
        self.middle(root.left)
        print(root.item)
        self.middle(root.right)
    def back(self, root):
        if root == None:
            return
        self.back(root.left)
        self.back(root.right)
        print(root.item)

        ●深度遍历的实现思路
                ■深度遍历是需要作用到每-颗子树中
                ■子树和子树之间的区别体现在根节点中。
                ■如果写一个函数,该函数可以将一个子树中的节点进行遍历,则将该函数作用到其他子树中就可以将整棵树进行深度遍历。(排序二叉树)
 

class SortTree():
    def __init__(self):
        self.root = None
    def add(self, item):  # 将节点插入到排序二叉树中
        node = Node(item)
        if self.root == None: # 树为空的情况
            self.root = node
            return
        cur =self.root
        while True:
        # 树为非空
            if cur.item > item: #  插入的节点值小于根节点,该节点需要插入到根节点的左侧
                if cur.left == None:
                    cur.left = node
                    break
                else:
                    cur = cur.left
            else: # 插入节点的值大等于于根节点,该节点需要插入到根节点的右侧
                if cur.right == None:
                    cur.right = node
                    break
                else:
                    cur = cur.right
    def middle(self, root):
        if root == None:
            return
        self.middle(root.left)
        print(root.item)
        self.middle(root.right)

二分查找:

        就是将顺序排序的列表进行二分查找,一半取值比较,再向上或向下查找

冒泡排序:

        两两比较,将数字大的放在后面。逐步将最大值放在最后。(双层循环)

●选择排序.
       1.将乱序序列中的元素两两比较,找出最大值,然后直接将最大值放置到序列最后的位置(双层循环)

●插入排序
        ●思路:
        ●需要将原始序列分成两部分:有序部分,无序部分
                ■将无序部分中的元素逐一插入到有序部分中,注意:初始情况下,有序部分为乱序序列的第一 个元素,无序部分为乱序序列的n-1个元素                                                                                              ■乱序序列: [3,8,5,7.6]   3就是初始的有序部分,8, 5, 7, 6就是初始的无序部分

def sort(alist) :
    for i in range(1, len(alist)):
        while i > 0:
            if alist[i-1] > alist[i]:
                alist[i-1], alist[i] = alist[i], alist[i-1]
                i -= 1
            else:
                break
    return alist

●希尔排序.
        ■关键变量:增量gap
        ■gap: 初始值为len(alist)//2
                。1.表示分组的组数
                。2.每一组数据之间的间隔
        ■插入排序就是增量为1的希尔排序

#  1.在插入排序代码中加入增量的概念
def sort(alist) :
    gap = len(alist) // 2 #初始增量
    #插入排序是增量为1的希尔排序
    #下述代码的增量为1,下述代码中的1表示的是增量
    """for i in range(1, len(alist)):
        while i > 0:
            if alist[i-1] > alist[i]:
                alist[i-1], alist[i] = alist[i], alist[i-1]
                i -= 1
            else:
                break"""
    #将插入排序中的增量1替换成gap
    #由增量为1变成了增量为gap了
    while gap >= 1:
        for i in range(gap, len(alist)):
            while i > 0:
                if alist[i-gap] > alist[i]:
                    alist[i-gap], alist[i] = alist[i], alist[i-gap]
                    i -= gap
                else:
                    break
        gap //= 2
    return alist

●快速排序.
        ■将列表中第一个元素设定为基准数字,赋值给mid变量,然后将整个列表中比基准小的数值
放在基准的左侧,比基准到的数字放在基准右侧。然后将基准数字左右两侧的序列在根据此
方法进行排放。
        ■定义两个指针, low指向最左侧,high指向最右侧
        ■然后对最右侧指针进行向左移动,移动法则是,如果指针指向的数值比基准小,则将指针指
向的数字移动到基准数字原始的位置,否则继续移动指针。
        ■如果最右侧指针指向的数值移动到基准位置时,开始移动最左侧指针,将其向右移动,如果
该指针指向的数值大于基准则将该数值移动到最右侧指针指向的位置,然后停止移动。
        ■如果左右侧指针重复则,将基准放入左右指针重复的位置,则基准左侧为比其小的数值,右
侧为比其大的数值。

def firstSort(alist, left, right):#1. 核心操作,将基数mid放置到序列中间, 使得基数左侧都是比它小的,右侧是比它大的
# eft和right表示当前sort递归作用到哪-一个子序列中
    low = left  # 第一个元素下标
    high = right  # 最后一个元素下标
    if low > high:
        return

    mid = alist[low]  # 基数
    while low != high:
        while low < high:
            if mid <= alist[high]:  # 向左偏移1,必须要有等于,不然有相同元素时,跳不出循环,下同,不然就得改变退出条件
                high -= 1
            else:
                alist[low] = alist[high]
                break
        while low < high:
            if mid >= alist[low]:
                low += 1
            else:
                alist[high] = alist[low]
                break
    alist[low] = mid
    #上述为核心操作,需要将核心操作递归左右到左右子序列中
    firstSort(alist, left, low-1) #将sort作用到左侧序列中
    firstSort(alist, high+1, right) #将sort作用到右侧序列中
    return alist


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值