递归,排序

Posted perfey

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归,排序相关的知识,希望对你有一定的参考价值。

面试题:

归并算法
	两个有序序列进行归并
	l1 = [1, 2, 5, 6, 8,10]
	l2 = [3, 4, 7,9,12]
	l3 = []
	i = 0
	j = 0

	while i < len(l1) and j < len(l2):
		if l1[i] < l2[j]:
			l3.append(l1[i])
			i += 1
		else:
			l3.append(l2[j])
			j = j + 1
	while i < len(l1):
		l3.append(l1[i])
		i += 1
	while i < len(l2):
		l3.append(l2[i])
		i += 1

	print(l3)

求阶乘后结果的末尾0的个数
	n= 5
	rus = 1
	while n>0:
		rus = rus*n
		n-=1
	s = str(rus)
	count =0
	s= ‘120000000‘
	for i in range(len(s)-1,-1,-1):
		if s[i]==‘0‘:
			count +=1
		else:
			break
	print(count)

字典排序:
	alist =[{‘name‘:‘a‘,‘age‘:20},{‘name‘:‘b‘,‘age‘:30},{‘name‘:‘c‘,‘age‘:25}]
	alist = sorted(alist,key=lambda dic:dic[‘age‘])
	print(alist)

斐波那契数列
a, b, c = 1, 2, 3
n = 400000
i = 0
while a < n:
	print(a)
	i += 1
	a, b, c = b, c, b + c
print(i)


def fib(n):
    li = [1,1]
    for i in range(2,n+1):
         li.append(li[-1]+li[-2])
    return li[-1]

def fib(n):
    if n ==0 or n == 1:
        return 1
    a = 1
    b = 1
    c = 1
    for i in range(2,n+1):
        a = b
        b = c
        c = a + b
    return c
	
# 青蛙跳台阶问题
def func(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    if n == 2:
        return 2
    return func(n - 1) + func(n - 2)


print(func(4))

递归
汉诺塔问题
def hanoi(n,A,B,C):
	if n>0:
		hanoi(n-1,A,C,B)
		print(‘%s -> %s‘ % (A,C))
		hanoi(n-1,B,A,C)
	hanoi(2,‘A‘,‘B‘,‘C‘)


二分查找
def bin_search(li, val):
	‘‘‘使用low和high标注索引,mid为中间索引,这里的索引代表指针,每次以中间值比较大小,比较完后改变索引‘‘‘
    low = 0
    high = len(li) - 1
    while low <= high:
        mid = (high - low) // 2
        if li[mid] > val:
            high = mid - 1
        elif li[mid] < val:
            low = mid + 1
        else:
            return mid
    return -1
	
	
	
使用and代替if语句
def func():
    print(‘aaa‘)

x = -3
x > 0 and func()
# 等价于
if x > 0:
    func()
# 所以可以使用and代替if语句()
# a and b <==> a if a == 0 else b
# a or b  <==> b if a == 0 else a



	
十种排序算法
# 推荐:https://blog.csdn.net/yangnianjinxin/article/details/77918882
选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法
low逼三人组

冒泡(稳定 o(n2))
# 走n趟,没趟交换比较选出最大的
def bubble_sort(li):
    for i in range(len(li) - 1):
        exchange = False   # 没有交换表示已经排好序了,就不用再继续执行了
        for j in range(len(li) - 1 - i):
            if li[j] > li[j + 1]:
                li[j], li[j + 1] = li[j + 1], li[j]
                exchange = True
        if not exchange:
            return


选择排序(不稳定)
# 一趟遍历选择记录中最小的数,放到第一个位置
# 再一趟遍历记录剩余列表中最小的数,继续放置

def select_sort(li):
    for i in range(len(li) - 1):
        min_pos = i
        for j in range(i + 1, len(li)):
            if li[j] < li[min_pos]:
                min_pos = j
        li[min_pos], li[j] = li[j], li[min_pos]

			
插入排序
# 列表分为有序区和无序区两个部分,最初有序区只有一个元素
# 每次从无序区选择一个元素,插入到有序区的位置,直到无序区变空
# 类似于玩纸牌时的插牌
# 可以优化空间使用二分查找来寻找插入点(并没有什么卵用)
def insert_sort(li):
    for i in range(1, len(li)): # 无序区
        j = i-1 # 有序区最后一个数
        tmp = li[i]
        while j >= 0 and li[j] > tmp: # 有序区从大到小逐一比较,直到有序区数小于li[i]
            li[j+1] = li[j]
            j -= 1
        li[j+1] = tmp		
		
牛逼三人组(o(nlogn))

快排
# 取一个元素p(第一元素),使元素p归位
# 列表被p分为两部分,左边的都比p小,右边的都比p大
# 递归完成排序
def _quick_sort(li, left, right):
    if left < right: # 至少两个元素
        mid = partition(li, left, right)
        _quick_sort(li, left, mid-1)
        _quick_sort(li, mid+1, right)


def quick_sort(li):
    _quick_sort(li, 0, len(li)-1)


def partition(li, left, right):
    i = random.randint(left, right)  # 随机选一个数,防止最坏情况
    li[left], li[i] = li[i], li[left]
    tmp = li[left]
    while left < right:
        while left < right and li[right] >= tmp:  #从右开始选,直到找到一个小于tmp的数,把这个数填在left位置
            right -= 1
        li[left] = li[right]
        while left < right and li[left] <= tmp:	  #从左开始选,直到找到一个大于tmp的数,把这个数填在right位置
            left += 1
        li[right] = li[left]
    li[left] = tmp
    return left
# 一行代码实现快排
# 这样空间复杂度会高
def quicksortshort(arr):
	return [] if arr==[] else quicksortshort([y for y in arr[1:] if y<arr[0]]) + [arr[0]]+ quicksortshort([y for y in arr[1:] if y>=arr[0]])

	
堆排
# 1,建立堆
# 2,得到堆顶元素,为最大元素
# 3,去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一个调整重新使堆有序
# 4,堆顶元素为第二大元素
# 5,重复步骤3,直到堆变空
def sift(li, low, high): # 调整,从子孩子中选出最大的和父节点比较,如果大于父节点就和父节点的值交换,然后父节点的值继续和子节点的子节点进行比较
    # low 表示根位置 high 表示最后元素的位置
    tmp = li[low]
    i = low # i指向空位
    j = 2 * i + 1 # j指向孩子
    # 把tmp写回来有两种条件 1. tmp > li[j]  2. j位置没有值 (也就是i已经是叶子了)
    while j <= high:    # 对应退出条件2
        if j + 1 <= high and li[j+1] > li[j]: # 如果右孩子存在且右孩子更大
            j += 1
        if li[j] > tmp:
            li[i] = li[j]
            i = j
            j = 2 * i + 1
        else:       # 对应退出条件1
            break
    li[i] = tmp
li = [3,5,6,2,0,4,1,9,8,7]
def heap_sort(li):
    n = len(li)
    # 1. 建立堆
    for low in range(n//2-1, -1, -1):
        # li = [3,5,6,2,0,4,1,9,8,7]
        ‘‘‘
                           3(索引0)
                    5(1)                   6(2)
              2(3)          0(4)        4(5)        1(6)
          9(7)   8(8)    7(9)
        ‘‘‘
        # 如 n=10时,low的值依次是 4,3,2,1,0 从最后的非叶子节点开始调整
        sift(li, low, n-1)
    print(li)  # 此时的li已经是一个大根堆了
    # [9, 8, 6, 5, 7, 4, 3, 0, 1, 2]
    ‘‘‘
                              9(索引0)
                       8(1)                   6(2)
                 5(3)          7(4)        4(5)        3(6)
             0(7)   1(8)    2(9)
           ‘‘‘
    # 2. 挨个出数 退休-棋子-调整
    for high in range(n-1, -1, -1):
        # high 的值 9,8,7,6,,5,4,3,2,1,0
        li[0], li[high] = li[high], li[0] # 这样交换后最大的就变到了列表的最后位置上,
        sift(li, 0, high-1) # 然后调整的时候就不把已经退休的(最大的)考虑在内了

		
python内置的堆模块
import heapq

li = [2,5,7,8,9,6,1,4,3]
heapq.heapify(li)  #调整变为小根堆
print(li)  # [1, 3, 2, 4, 9, 6, 7, 5, 8]
heapq.heappush(li, 0)  # 插入新值,自动调整为小根堆
print(li)  # [0, 1, 2, 4, 3, 6, 7, 5根堆, 8, 9]
print(heapq.heappop(li))  # 堆顶退休(最小值),继续调整为小
print(heapq.heappop(li))

print(heapq.nlargest(5, li))  # 输出最大的5个数
# [9, 8, 7, 6, 5]
print(heapq.nsmallest(5, li)) # 输出最小的5个数
# [2, 3, 4, 5, 6]

列表中取出前k大的数
# 1,取列表前k个元素建立一个小根堆,堆顶就是这个堆中最小的数,也是这个堆中第k大的数
# 2,依次向后遍历原列表,对于列表中的元素,如果小于堆顶,则忽略该元素,如果大于堆顶则将堆顶更换为改元素,并且对堆进行一次调整
# 3,遍历列表所有元素后,倒序弹出堆顶		
		
归并
def merge(li, low, mid, high):
    li_tmp = []
    i = low
    j = mid + 1
    while i <= mid and j <= high:
        if li[i] <= li[j]:
            li_tmp.append(li[i])
            i += 1
        else:
            li_tmp.append(li[j])
            j += 1
    while i <= mid:
        li_tmp.append(li[i])
        i += 1
    while j <= high:
        li_tmp.append(li[j])
        j += 1
    for i in range(len(li_tmp)):  # 把归并排好的两个列表放回到li中
        li[i+low] = li_tmp[i]


def _merge_sort(li, low, high):
    if low < high: # 2个元素及以上
        mid = (low + high) // 2
        _merge_sort(li, low, mid)
        _merge_sort(li, mid+1, high)
        #print(li[low:mid+1], li[mid+1:high+1])
        merge(li, low, mid, high)
        #print(li[low:high + 1])

def merge_sort(li):
    _merge_sort(li, 0, len(li)-1)


没什么人用的排序
基数排序
希尔排序
桶排序


二叉树
列表中索引:父节点 -> 左孩子节点   i -> 2i+1
		   父节点 -> 右孩子节点   i -> 2i+2
		   孩子节点 -> 父节点     i -> (i-1)//2
		   堆顶  i = 0 
		   所有父节点 i_list =[i for i in range(len(li)//2)] 
大根堆:一个完全二叉树,满足任一节点都比其孩子节点大
小根堆:一个完全二叉树,满足任一节点都比其孩子节点小
当根节点的左右子树都是堆时(这里的示例是大根堆),可以通过一次向下调整来将其变换成一个堆

  

技术分享图片

 

以上是关于递归,排序的主要内容,如果未能解决你的问题,请参考以下文章

八大排序 (万字总结)(详细解析,建议收藏!!!)

JavaScript - 代码片段,Snippets,Gist

Java快速排序的非递归实现

8种面试经典!排序详解--选择,插入,希尔,冒泡,堆排,3种快排,快排非递归,归并,归并非递归,计数(图+C语言代码+时间复杂度)

8种面试经典排序详解--选择,插入,希尔,冒泡,堆排,3种快排及非递归,归并及非递归,计数(图+C语言代码+时间复杂度)

8种面试经典排序详解--选择,插入,希尔,冒泡,堆排,3种快排及非递归,归并及非递归,计数(图+C语言代码+时间复杂度)