数据结构 --- 01. 时间复杂度,timeit模块,栈,队列,双端队列

一.时间复杂度

  1.基本概念

评判程序优劣的方法:
  消耗计算机资源和执行效率(无法直观)
  计算算法执行的耗时(适当推荐,因为会受机器和执行环境的影响)
  时间复杂度(推荐)
时间复杂度
  评判规则:量化算法执行的操作
/执行步骤的数量   最重要的项:时间复杂度表达式中最有意义的项   大O记法:O(时间复杂度表达式中最有意义的项)

常见的时间复杂度:
  • O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
 

  2.示例说明

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记法:
O(n**2)

def sumOfN(n):
    theSum = 0
    for i in range(0,n+1):
        theSum = theSum + i

    return theSum

print(sumOfN(10))
用大O记法:

O(n)

③三种不同数据结构的时间复杂度

[
    ['tom',100],['jay',99]
]
#O(n)
[
    ('tom',100),('jay',99)
]
#O(n)
{
    'tom':{'score':100},
    'jay':{'score':100},
}
#O(1)

二.timeit(测试代码执行的平均值)

timeit模块:该模块可以用来测试一段python代码的执行速度/时长。
      计算运行平均耗时


Timer类:该类是timeit模块中专门用于测量python代码的执行速度/时长的。原型为:class timeit.Timer(stmt='pass',setup='pass')。

  stmt参数:表示即将进行测试的代码块语句。

  setup:运行代码块语句时所需要的设置。

  timeit函数:timeit.Timer.timeit(number=100000),该函数返回代码块语句执行number次的平均耗时。
示例:实例化一个空列表,然后将0-n范围的数据添加到列表中。
from timeit import Timer
def test01(): alist
= [] for i in range(1000): alist.append(i) def test02(): alist = [] for i in range(1000): alist += [i] def test03(): alist = [i for i in range(1000)] def test04(): alist = list(range(1000)) def test05(): alist = [] for i in range(1000): alist.insert(i,i) if __name__ == '__main__': timer = Timer(stmt='test01()',setup='from __main__ import test01') print(timer.timeit(1000)) timer = Timer(stmt='test02()',setup='from __main__ import test02') print(timer.timeit(1000)) timer = Timer(stmt='test03()',setup='from __main__ import test03') print(timer.timeit(1000)) timer = Timer(stmt='test04()',setup='from __main__ import test04') print(timer.timeit(1000)) timer = Timer(stmt='test05()',setup='from __main__ import test05') print(timer.timeit(1000))
结果:

0.0837575913687374
0.08196741393689422 0.03640777904436732 0.014782621075369207 0.16312698009613769

三.  栈

特性:先进后出的数据结构

  1.基本操作

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

  2.示例:

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 self.items[-1]
    def isEmpty(self):
        return self.items == []
    def size(self):
        return len(self.items)

s = Stack()
s.push('jay')
s.push(123)
s.push('haha')
print(s.pop())
print(s.pop())
print(s.isEmpty())
print(s.size())
print(s.peek())
结果:

haha
123 False 1 jay

应用:每个 web 浏览器都有一个返回按钮。当你浏览网页时,这些网页被放置在一个栈中(实际是网页的网址)。

你现在查看的网页在顶部,你第一个查看的网页在底部。如果按‘返回’按钮,将按相反的顺序浏览刚才的页面。
s = Stack()
def request(url):
    s.push(url)
def back():
    return s.pop()
def current_page():
    print(s.pop())

request('www.1.com')
request('www.2.com')
request('www.3.com')

current_page()
back()
back()
结果:

www.3.com 'www.1.com'

四. 队列

  1.基本概念

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

  2.基本操作

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

  3.示例

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)
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)

print(q.dequeue())
print(q.dequeue())
结果:

1
2

 

案例:烫手的山芋
  烫手山芋游戏介绍:6个孩子围城一个圈,排列顺序孩子们自己指定。
  第一个孩子手里有一个烫手的山芋,需要在计时器计时1秒后将山芋传递给下一个孩子,
  依次类推。规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。该游戏直到剩下一个孩子时结束,
  最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜。

q = Queue()
alist = ['a','b','c','d','e','f']
for i in alist:
    q.enqueue(i)

while q.size() > 1:
    for i in range(6):
        kid = q.dequeue()
        q.enqueue(kid)
    q.dequeue()
    
print(q.dequeue())
结果:

    e

五,双端队列

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

  1.基本操作

Deque() 创建一个空的新 deque。它不需要参数,并返回空的 deque。
addFront(item) 将一个新项添加到 deque 的首部。它需要 item 参数 并不返回任何内容。
addRear(item) 将一个新项添加到 deque 的尾部。它需要 item 参数并不返回任何内容。
removeFront() 从 deque 中删除首项。它不需要参数并返回 item。deque 被修改。
removeRear() 从 deque 中删除尾项。它不需要参数并返回 item。deque 被修改。
isEmpty() 测试 deque 是否为空。它不需要参数,并返回布尔值。
size() 返回 deque 中的项数。它不需要参数,并返回一个整数。

   2.示例:回文检查

双端队列应用案例:回文检查
回文是一个字符串,读取首尾相同的字符,例如,radar toot madam。
class Deque():
    def __init__(self):
        self.items = []
    def addFont(self,item):
        self.items.append(item)
    def addRear(self,item):
        self.items.insert(0,item)
    def removeFont(self):
        return self.items.pop()
    def removeRear(self):
        return self.items.pop(0)
    def isEmpty(self):
        return self.items == []
    def size(self):
        return len(self.items)
def isHuiWen(word):
    ex = True
    q = Deque()
    for ch in word:
        q.addFont(ch)
    while q.size() > 1:
        if q.removeFont() != q.removeRear():
            ex = False
            break
    return ex
print(isHuiWen('abbaa'))
结果:

False

猜你喜欢

转载自www.cnblogs.com/sc-1067178406/p/10960510.html