一、冒泡排序的思想
冒泡排序的过程,就好像咱们喝汽水时,那些小气泡一点一点从下往上的冒,最后到了最顶部。
这只是一种形象的类比,用实际的例子来说明一下。假如有一个列表,其中的数字是无序排列的,
通过冒泡要实现的结果就是将列表中的数字从小到大排序。
那么怎么实现呢?我们可以将列表中左侧第一个和第二个数字先进行比较,将较小的排在左侧;
然后再比较第二个和第三个数字,较小的排在左侧,再比较第三个和第四个......将列表中的数字第一轮比较完之后,
最大的数,排在了列表的最尾端。然后重复上面的步骤,但是尾端最大的数不再参与比较,一轮一轮的比较完之后,
实现将列表中的数字从小到大排序后的效果。这样是不是最小的数一点一点从后往前冒了呢?
冒泡的最优时间复杂度为O(n),最坏时间复杂度为O(n^2)。空间复杂度为O(1)。
那么下面使用代码实现一个冒泡排序:
list1 = [3, 7, 5, 1, 6, 2]
n = len(list1)
for x in range(n-1):
for y in range(n-1-x):
if list1[y] > list1[y+1]:
list1[y], list1[y+1] = list1[y+1], list1[y]
print(list1)
二、快速排序的思想
快速排序的方法和冒泡排序类似,也属于交换排序。也就是通过不断的比较元素之间的大小,
同时不断的交换元素的位置,实现排序的效果。那么它为什么叫快速排序呢?因为它快啊!(......很欠揍的样子)
我们简单的了解一下快速排序。快速排序就是先找到一个基准(一般来说拿列表中的第一个元素先做为基准),
然后利用这个基准,将列表中的元素分为两部分。一部分(这部分中的元素每一个都要比基准大)放在基准的右侧;
另一部分(这一部分中的元素都比基准小)放在基准左侧。第一轮划分完毕,第二轮会将左部分和右部分再次进行第一轮的步骤。
然后不断的划分啊划分啊划分啊......直到最后列表中的元素变成了有序,就结束排序。
看到了上面的步骤是不是发现一个问题?这不就是我们的递归思想吗?对的,稍后我们就利用递归的方法实现一个快速排序。
快速排序的最优时间复杂度为O(nlogn),最坏时间复杂度为O(n^2),空间复杂度为O(logn)。它是不稳定的。
下面使用代码实现一个快速排序:
def quick_sort(list1, left, right):
if left >= right:
return None
n = left
m = right
base = list1[n]
while n < m:
# 从右边往左边找一个比base小的
while list1[m] >= base and n < m:
m -= 1
if n == m:
list1[n] = base
else:
# 拿小的值填前面的坑
list1[n] = list1[m]
# 从左边往右边找一个比base大的
while list1[n] <= base and n < m:
n += 1
if n == m:
list1[n] = base
else:
list1[m] = list1[n]
# 对左边的进行快排
quick_sort(list1, left, n-1)
# 对右边的进行快排
quick_sort(list1, n+1, right)
if __name__ == '__main__':
list1 = [3, 7, 5, 1, 6, 2]
quick_sort(list1, 0, len(list1)-1)
print(list1)
三、插入排序
插入排序是一种简单直观的排序方法,我想说一句废话(插入排序就是通过插入来实现排序),想了想还是忍住了。
插入排序的思路是什么样的呢?下面且听我慢慢道来。
有一个无序列表,让我们将其中的元素从小到大进行排序。使用插入排序,首先将从左到右的第一个元素所在的区域叫做有序区,
其他的元素在的区域叫做无序区。然后将无序区中的元素从左到右开始取,取出来一个元素就将其放在有序区的合适位置
(比如无序区取了一个3,有序区有两个数字1和4,那么我们就将3放到1和4之间)。不断的从无序区取,向有序区合适位置插,
直到最后无序区没有值了,列表也就变成了有序列表。
最优时间复杂度为O(n),最坏时间复杂度为O(n^2),具有稳定性。
那么用代码实现一个插入排序:
def insert_Sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
print(arr)
if __name__ == '__main__':
arr = [12, 11, 13, 5, 6, 1]
insert_Sort(arr)
四、二分查找法:
def binary_find(list1, key, m, n):
while m <= n:
# 先找到中间的值
mid = (m+n)//2
# 拿key和中间值进行比较
# 如果key比中间值小,则说明key可能在左半部分
if key < list1[mid]:
# 左下标不动 右下标n = mid -1
n = mid - 1
# 对左半部分就行二分查找
return binary_find(list1, key, m, n)
# 如果key比中间值大,则说明key可能在右半部分
elif key > list1[mid]:
# 右下标不动, 左下标 m = mid + 1
m = mid + 1
# 对右半部分进行二分查找
return binary_find(list1, key, m, n)
else:
return mid
return -1
if __name__ == "__main__":
list1 = [2, 4, 6, 8, 10, 12, 14, 16, 18]
while True:
key = int(input("请输入需要查找的数字:"))
index = binary_find(list1, key, 0, len(list1)-1)
print(index)
五、约瑟夫环
list1 = [1, 2, 3, 4, 5, 6, 7, 8]
n = 1
x = 0
while True:
if x == len(list1):
x = 0
while x < len(list1):
if n % 3 == 0:
list1.pop(x)
n += 1
print(list1)
break
else:
n += 1
x += 1
if len(list1) == 1:
break
'''1.韩信点兵:韩信有一队兵,他想知道有多少人,
便让士兵排队报数:按从1至5报数,最末一个士兵报的数为1;
按从1至6报数,最末一个士兵报的数为5;
按从1至7报数,最末一个士兵报的数为4,
请问士兵有多少
'''
# for x in range(1, 1000):
# if x % 5 == 1 and x % 6 == 4 and x % 7 == 4:
# print(x)
'''
2、相传韩信才智过人,从不直接清点自己的军队的人数,
只要让士兵先后以三人一排、五人一排、七人一排变换队形,
便知道队伍的总人数,设队尾人数分别为输入的三个非负整数a,b,c(a<3,b<5,c<7),
输出总人数(或无解),总人数为10~100人。
'''
# a = int(input("输入一个数:"))
# b = int(input("输入一个数:"))
# c = int(input("输入一个数:"))
# for x in range(10, 100):
# if 0 < a < 3 and 0 < b < 5 and 0 < c < 7:
# if x % 3 == a and x % 5 == b and x % 7 == c:
# print(x)
# break
# else:
# print("无解")
'''
3、尼科彻斯定理:一个整数的立方都可以写成一串连续奇数的和.例如:
1的立方=1
2的立方=3+5
3的立方=7+9+11
4的立方=13+15+17+19
请编程验证该定理(在键盘上输入任意一个数字都能够表示成一串连续奇数的和,
并且将这一串奇数打印出来)
'''
# n = int(input("输入一个整数:"))
# #创建一个列表存储每一项
# list = []
# #第一项
# a = n ** 2 - (n - 1)
# #第二项比第一项大2,最后一项a +(n -1)*2
# for i in range(a, a + n*2, 2):
# list.append(i)
# print(list)
'''
4、幼儿园老师将糖果分成若干等份,让学生按任意次序领取
,第1个领取的,得到1份加上剩余糖果的1/10;
第2个领取的,得到2份加上剩余糖果的1/10;
第3个领取的,得到3份加上剩余糖果的1/10,........依次类推。
问共有多少个学生?老师将糖果分成了多少等份?
'''
# n = 11
# while True:
# s1 = (n+9)/10
# s2 = (9*n+171)/100
# if s1 == s2:
# break
# else:
# n += 1
# # print("糖果的份数", n)
# # print("学生的数目", int(n/s1))
# print("糖果份数为:", n, "学生数为:", int(n/s1))
'''
5、如果整数A的全部因子(包括1,不包括A本身)之和等于B;
且整数B的全部因子(包括1,不包括B本身)之和等于A,
则将整数A和B称为亲密数。求3000以内的全部亲密数。
'''
#将A的全部因子和 赋值给B, 如果B的所有因子和等于A 说明A和B就是亲密数
# for A in range(1, 3000):
# B = 0
# sum = 0
# for x in range(1, A):
# if A % x == 0:
# B += x
# for y in range(1, B):
# if B % y == 0:
# sum += y
# if sum == A and A <= B:
# print(A, B)
'''
1.一个数如果恰好等于它的因子之和,这个数就称为“完数”。
例如6=1+2+3.编程找出1000以内的所有完数
'''
# for i in range(2, 1000):
# l1 = []
# for j in range(1, i):
# if i % j == 0:
# l1.append(j)
# num = sum(l1)
# if num == i:
# print(i)
'''
2、在键盘输入一个5位数,判断它是不是回文数。
即12321是回文数,个位与万位相同,十位与千位相同。
'''
# def huiwen():
# x = int(input("输入一个五位数:"))
# a = x // 10000
# b = x // 1000 % 10
# c = x // 10 % 10
# d = x % 10
# if a == d and b == c:
# print('yes')
# else:
# print('no')
# if __name__ == "__main__":
# huiwen()
'''
3.在键盘上输入个坐标x,y,再输入一个半径r,
请打印出以(x,y)作为圆心,半径为r的圆内的所有的点的坐标
4.从键盘上输入若干个单词,单词和单词之间用空格隔开,
编程统计单词的个数
空格数加一就是单词个数
'''
src = "h12lo wabld abc abc"
cnt = 0
flag = 1 #默认是单词
blank = 1 # 假设是空格
for x in range(len(src)):
# 判断一个字符不是字母
if src[x] < 'A' or src[x] > 'z' or (src[x] > 'Z' and src[x] < 'a'):
# if src[x]>='A' and src[x] <= 'Z' or src[x]>='a' and src[x] <= 'z':
# 并且不是空格
if src[x] != ' ':
flag = 0 #不是个单词
blank = 0
else: # 当前字符是个空格
# 如果是连续的空格,直接遍历下一个字符
if blank == 1:
continue
#前面的组合是个单词
if flag == 1:
cnt += 1
#假设后面的组合是单词
flag = 1
blank = 1
else: # 当前字符是字母
blank = 0 # 当前字符不是空格
#如果最后一个元素不是空格 并且flag == 1
if blank == 0 and flag == 1:
cnt += 1
print(cnt)
'''
5、猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,
还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,
又多吃了一个。以后每天早上都吃了前一天剩下
的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。
求第一天共摘了多少。
'''
# def fun(n):
# if n == 1:
# return 1
# return (fun(n-1)+1)*2
#
# if __name__ == "__main__":
# print(fun(10))