冒泡排序
步骤
(1) 指向数组中两个相邻的元素(最开始是数组的头两个元素),比较它们的大小。
(2) 如果它们的顺序错了(即左边的值大于右边),就互换位置。[插图]如果顺序已经是正确的,那这一步就什么都不用做。
(3) 将两个指针右移一格。
重复第(1)步和第(2)步,直至指针到达数组末尾。
(4)重复第(1)至(3)步,直至从头到尾都无须再做交换,这时数组就排好序了。
实现
def bubble_sort(list):
unsorted_until_index = len(list)-1
sorted = False
while not sorted:
sorted=True
for i in range(unsorted_until_index):
if list[i] >list[i+1]:
sorted = False
list[i],list[i+1] = list[i+1],list[i]
unsorted_until_index = unsorted_until_index -1
list = [1,5,8,3,4,6]
bubble_sort(list)
print(list)
效率
冒泡排序效率的大O记法,是 O ( N 2 O(N^2 O(N2),也被叫作二次时间
选择排序
步骤
(1) 从左至右检查数组的每个格子,找出值最小的那个。在此过程中,我们会用一个变量来记住检查过的数字的最小值(事实上记住的是索引,但为了看起来方便,下图就直接写出数值)。如果一个格子中的数字比记录的最小值还要小,就把变量改成该格子的索引,如图所示。
(2) 知道哪个格子的值最小之后,将该格与本次检查的起点交换。第1次检查的起点是索引0,第2次是索引1,以此类推。下图展示的是第一次检查后的交换动作。
(3) 重复第(1) (2)步,直至数组排好序。
实现
def selectionSort(list):
for i in range(len(list)):
lowestNumber = i
j = i+1
for j in range(len(list)-1):
if list[j]>list[lowestNumber]:
lowestNumber = j
if lowestNumber!=i:
temp = list[i]
list[i]=list[lowestNumber]
list[lowestNumber] = temp
print(list)
return list
list = [1,5,8,3,4,6]
selectionSort(list)
print(list)
效率
选择排序的步骤分为两类,比较和交换,下图是冒泡排序与选择排序的步骤比较
选择排序的步数大概只有冒泡的一半,但是,选择排序的大O计数与冒泡计数是一样的。都是 O ( N 2 O(N^2 O(N2)
注意: 大O记法忽略常数。大O记法只表明,对于不同分类,存在一临界点,在这一点之后,一类算法会快于另一类,并永远保持下去。至于这个点在哪里,大O并不关心。虽然选择排序比冒泡排序快1倍,但它们的大O记法都是
O
(
N
2
)
O(N^2)
O(N2)。所以,主要结论是即使两种算法的大O记法一样,但实际速度也可能并不一样。
插入排序
步骤
(1) 在第一轮里,暂时将索引1(第2格)的值移走,并用一个临时变量来保存它。这使得该索引处留下一个空隙,因为它不包含值。
在之后的轮回,我们会移走后面索引的值。
(2) 接着便是平移阶段,我们会拿空隙左侧的每一个值与临时变量的值进行比较。[插图]如果空隙左侧的值大于临时变量的值,则将该值右移一格。
随着值右移,空隙会左移。如果遇到比临时变量小的值,或者空隙已经到了数组的最左端,就结束平移阶段。
(3) 将临时移走的值插入当前空隙。
(4) 重复第(1)至(3)步,直至数组完全有序。
def selectionSort(list):
for i in range(len(list)):
lowestNumber = i
j = i+1
for j in range(len(list)-1):
if list[j]>list[lowestNumber]:
lowestNumber = j
if lowestNumber!=i:
temp = list[i]
list[i]=list[lowestNumber]
list[lowestNumber] = temp
return list
list = [1,5,8,3,4,6]
selectionSort(list)
print(list)
栈
栈:先入后出(LIFO) 数据的处理顺序要与接收顺序相反时(LIFO),用栈就对了。像文字处理器的“撤销”动作,或网络应用程序的函数调用,都会需要栈来实现。
- Stack()创建一个空栈。它不需要参数,且会返回一个空栈。❏ push(item)将一个元素添加到栈的顶端。它需要一个参数item,且无返回值。
- pop()将栈顶端的元素移除。它不需要参数,但会返回顶端的元素,并且修改栈的内容。
- peek()返回栈顶端的元素,但是并不移除该元素。它不需要参数,也不会修改栈的内容。
- isEmpty()检查栈是否为空。它不需要参数,且会返回一个布尔值。
- size()返回栈中元素的数目。它不需要参数,且会返回一个整数。
class Stack:
def __init__(self) -> None:
self.items = []
def isEmpty(self):
return self.items == []
def push(self,item):
return self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
s = Stack()
print(s.isEmpty())
s.push('dog')
print(s)
s.push(4)
print(s.peek())
print(s.size())
# 括号匹配
import sys ,os
sys.path.append(os.path.dirname(__file__))
print(sys.path)
from Stack import Stack
def parCheacher(sym):
s = Stack()
balanced = True
index = 0
while index < len(sym) and balanced:
symbol = sym[index]
if symbol == '(':
s.push(symbol)
else:
if s.isEmpty():
balanced=False
else:
s.pop()
index = index+1
if balanced and s.isEmpty():
return True
else:
return False
parCheacher('()()()))(')
print(parCheacher('()()()))('))
将十进制转为2进制
import sys ,os
sys.path.append(os.path.dirname(__file__))
print(sys.path)
from Stack import Stack
def dividepy2(decNumber):
remstack = Stack()
while decNumber>0:
rem = decNumber%2
remstack.push(rem)
decNumber = decNumber//2
binString = ''
while not remstack.isEmpty():
binString = binString+str(remstack.pop())
return binString
print(dividepy2(109))
队列(FIFO)
最新添加的元素必须在队列的尾部等待,在队列中时间最长的元素则排在最前面。这种排序原则被称作FIFO(first-in first-out),即先进先出,也称先到先得。
- Queue()创建一个空队列。它不需要参数,且会返回一个空队列。
- enqueue(item)在队列的尾部添加一个元素。它需要一个元素作为参数,不返回任何值。
- dequeue()从队列的头部移除一个元素。它不需要参数,且会返回一个元素,并修改队列的内容。
- isEmpty()检查队列是否为空。它不需要参数,且会返回一个布尔值。
- size()返回队列中元素的数目。它不需要参数,且会返回一个整数
from Queue import Queue
def hotPotato(namelist,num):
simqueue = Queue() #空队列
for name in namelist:
simqueue.enqueue(name) # 添加在队尾
while simqueue.size>1:
for i in range(num):
simqueue.enqueue(simqueue.dequeue()) #移除队列的头部
simqueue.dequeue()
return simqueue.dequeue()