数据结构-排序/二分查找

1.排序

实现归并排序、快速排序、插入排序、冒泡排序、选择排序、堆排序(选做)(完成leetcode上的返回滑动窗口中的最大值(239)

0.1 算法分类

排序算法可以分为两大类
比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
在这里插入图片描述

0.2 算法复杂度

在这里插入图片描述

0.3 相关概念

稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
空间复杂度:是指算法在计算机
内执行时所需存储空间的度量,它也是数据规模n的函数。

以上内容来自以下链接:
https://www.cnblogs.com/onepixel/articles/7674659.html

1.1 冒泡排序

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

1.1 算法描述

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  • 针对所有的元素重复以上的步骤,除了最后一个;
  • 重复步骤1~3,直到排序完成。

1.2 代码实现

# In[]
def bubbling_sort(lista):
    for i in range(len(lista)-1):
        for j in range(len(lista)-i-1):
            if lista[j]>lista[j+1]:
                temp=lista[j]
                lista[j]=lista[j+1]
                lista[j+1]=temp
    return lista
listb=bubbling_sort(lista)

1.2 快速排序

上面参考链接详细展示了十大经典排序算法(动图演示)快速排序法的核心思想是选定一个基准点后,两个哨兵往中间移动,对比与基准点的大小关系来决定是否要交换数值。一般来说,基准点是最左端的位置,当然也可以产生随机基准点。、、
注意要右边先移动,次序很重要
详细的原理解析见参考链接:
https://blog.csdn.net/sinat_20177327/article/details/76560079#commentBox

def swap(arr,a,b):    
    temp=arr[a]
    arr[a] = arr[b]
    arr[b] = temp
    return arr

def fastsort(arr,left,right):
    if left>=right:
        return
    i=left
    j=right
    temp=arr[left]
    while i!=j:
        while arr[j]>=temp and i<j:    # 右边的先动,这个很关键
            j-=1
        while arr[i]<=temp and i<j:
            i+=1    
        if i<j:
            swap(arr,i,j)
    if arr[i]<temp:    ## i==j时,判断相遇点与temp(基准)的大小
        swap(arr,left,i)
    fastsort(arr,left,i-1)
    fastsort(arr,i+1,right)
 # In[] 
#arr=[7,6,5,8]  
arr = [1,4,7,2,3,6,5,8]
fastsort(arr,0,len(arr)-1)

参考链接:

https://blog.csdn.net/sinat_20177327/article/details/76560079#commentBox

还有 堆排序、 归并排序、插入排序、选择排序等,后续再展开

1.3 滑动窗口中的最大值

leetcode上的返回滑动窗口中的最大值(239)
在这里插入图片描述
这题目用python 来写真的挺简单的

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        s=[]
        if nums==[]:
            return []
        elif len(nums)<=k:
            s.append(max(nums))
            return s
        else:            
            for i in range(len(nums)-k+1):
                s.append(max(nums[i:i+k]))
            return(s)

1.4 第K 大元素

编程实现 O(n) 时间复杂度内找到一组数据的第 K 大元素(面试遇到了此问题)
结合快速排序法,排完第一轮后, left 和 right 指针相遇时,判断一下后半段的长度L与K 的大小关系,如果K 值比L 大,那么从左半段中继续寻找(K-L)大值,否则,从右半段中寻找第K大元素 开始新一轮的快速排序,直到找完第K大元素。

def swap(arr,a,b):    
    temp=arr[a]
    arr[a] = arr[b]
    arr[b] = temp
    return arr

def Find_Max_K(arr,left,right,K):
#    if left>=right:
#        return
    i=left
    j=right
    temp=arr[left]
    while i!=j:
        while arr[j]>=temp and i<j:    # 右边的先动,这个很关键
            j-=1
        while arr[i]<=temp and i<j:
            i+=1    
        if i<j:
            swap(arr,i,j)
    if arr[i]<temp:    ## i==j时,判断相遇点与temp(基准)的大小
        swap(arr,left,i)

    if i==K:
        print("第%d大值是:%d"%((len(arr)-K),arr[i]))
        return i
    elif i<K:
        Find_Max_K(arr,i+1,right,K)
    else:
        Find_Max_K(arr,left,i-1,K)
  
     # In[] 
#arr=[7,6,5,8]  
arr = [4,1,2,7,9,3,6,5,10,8]
mark=2
K=len(arr)-mark
Find_Max_K(arr,0,len(arr)-1,K)

在这里插入图片描述

2. 二分查找

二分查找常用的有这么七种:

①是否 存在数字t ——返回下标或者-1

②找到 大于t的第一个数 ——返回下标或者-1

③找到 大于等于t的第一个数 ——返回下标或者-1

④找到 小于t的第一个数 ——返回下标或者-1

⑤找到 小于等于 t的第一个数 ——返回下标或者-1

⑥是否 存在数字t,返回 第一个t ——返回下标或者-1

⑦是否 存在数字t,返回 最后一个t ——返回下标或者-1

2.1 代码实现

①是否 存在数字t ——返回下标或者-1
这是最简单原始的二分查找

# In[] 是否 存在数字t  ——返回下标或者 False
def findData(lista,target):
    left=0
    right=len(lista)
    m_last=0
    while left<=right:        
        m=int((left+right)/2)
        if m_last==m:
            break       
        if lista[m]==target:
            return m
        elif lista[m]<target:
            left=m
        else:
            right=m
        m_last=m
    return False

print(findData(lista,target))

②找到 大于t的第一个数 ——返回下标或者-1

# In[] 找出大于t的第一个数
def findData_2(lista,target):
    left=0
    right=len(lista)
    m_last=0
#    mark=0
    while left<=right:        
        m=int((left+right)/2)    
        if m_last==m or lista[m]==target:
            break
        elif lista[m]<target:
            left=m
        else:
            right=m
        m_last=m

    if m==len(lista):
        return m
    else:
        while m<len(lista):
            if lista[m]>target:
                return m
            m+=1  
        return False      
print(findData_2(lista,target))

③找到 大于等于t的第一个数 ——返回下标或者-1

# In[] 找出大于等于t的第一个数
def findData_3(lista,target):
    left=0
    right=len(lista)
    m_last=0
#    mark=0
    while left<=right:        
        m=int((left+right)/2)    
        if m_last==m or lista[m]==target:
            break
        elif lista[m]<target:
            left=m
        else:
            right=m
        m_last=m

    if lista[m]==target:   # 当前位置的值是target,往前去寻找第一个target 值
        while m>=0:
            if lista[m]<target:
                return m+1
            m-=1
    else:
        while m<len(lista):   # 没有找到等于target值的位置,往前找第一个大于target值的数
            if lista[m]>target:
                return m
            m+=1 
        return False
print(findData_3(lista,target))

④找到小于的第一个数 ——返回下标或者-1

# In[] 找到 小于t的第一个数 ——返回下标或者-1
def findData_4(lista,target):
    left=0
    right=len(lista)
    m_last=0
#    mark=0
    while left<=right:        
        m=int((left+right)/2)    
        if m_last==m or lista[m]==target:
            break
        elif lista[m]<target:
            left=m
        else:
            right=m
        m_last=m

    if  m==0:
        if lista[m]<target:  #若当前位置是第一位,且数值比target值小,那么返回第一位,否则False
            return m
        else:
            return False
    else:
        while m>=0:        #若当前位置不是第一位, 向前找出最靠近target的一位
            if lista[m]<target:
                return m
            m-=1 
        return False
print(findData_4(lista,target))

⑤找到小于等于 t的第一个数 ——返回下标或者-1

# In[] 找到 小于等于t的第一个数 ——返回下标或者-1
def findData_5(lista,target):
    left=0
    right=len(lista)
    m_last=0
#    mark=0
    while left<=right:        
        m=int((left+right)/2)    
        if m_last==m or lista[m]==target:
            break
        elif lista[m]<target:
            left=m
        else:
            right=m
        m_last=m
        
    print(m)
        
    if m==0:
        if lista[m]<=target:
            return m
        else:
            return False   # 当前位置的值是target,往前去寻找第一个target 值
    else:
        if lista[m]==target: # 当前位置的值是target,往前去寻找第一个target 值
            while m>=0:
                if lista[m]<target:
                    return m+1
                print(m)
                m-=1 
                
        else:    
            while m>=0:   # 没有找到等于target值的位置,往前找第一个小于target值的数
                if lista[m]<target:
                    return m
                m-=1 
            return False

print(findData_5(lista,target))

⑥是否 存在数字t,返回 第一个t ——返回下标或者-1

# In[] 是否 存在数字t,返回 第一个t ——返回下标或者-1
def findData_6(lista,target):
    left=0
    right=len(lista)
    m_last=0
#    mark=0
    while left<=right:        
        m=int((left+right)/2)    
        if m_last==m or lista[m]==target:
            break
        elif lista[m]<target:
            left=m
        else:
            right=m
        m_last=m

    if lista[m]==target:   # 当前位置的值是target,往前去寻找第一个target 值
        while m>=0:
            if lista[m]<target:
                return m+1
            m-=1
    else:
        return False   ## 没有找到该值,返回-1
print(findData_6(lista,target))

⑦是否 存在数字t,返回 最后一个t ——返回下标或者-1

# In[] 是否 存在数字t,返回 最后t ——返回下标或者-1
def findData_7(lista,target):
    left=0
    right=len(lista)
    m_last=0
#    mark=0
    while left<=right:        
        m=int((left+right)/2)    
        if m_last==m or lista[m]==target:
            break
        elif lista[m]<target:
            left=m
        else:
            right=m
        m_last=m

    if lista[m]==target:   # 当前位置的值是target,往后去寻找最后target 值
        if m==len(lista):  # 若当前位置已是最末端,return
            return m
        else:            
            while m<len(lista):
                if lista[m]>target:
                    return m-1
                m+=1
    else:
        return False   ## 没有找到该值,返回-1
print(findData_7(lista,target))

参考链接

https://blog.csdn.net/Hide_in_Code/article/details/76549317

2.7 sqrt函数的实现

Sqrt(x) (x 的平方根)

英文版:https://leetcode.com/problems/sqrtx/
中文版:https://leetcode-cn.com/problems/sqrtx/

class Solution:
    def mySqrt(self, x: int) -> int:
        if x==1 or x==0:
            return x
        else:
            left=0
            right=x
            while left<right:
                temp=(left+right)/2
                if int(temp)**2<=x and int((temp+1))**2>=x:                
                    if int((temp+1))**2==x:
                        temp=int((temp+1))
                    return(int(temp))
                    break        
                elif int(temp)**2<x and int(temp+1)**2<x:
                    left=temp             
                else:
                    right=temp

在这里插入图片描述

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值