算法及数据结构

排序算法之快排序

实现原理:
话不多说,直接上代码,唯美暴力:

"""
实现原理:
一个至少有两个数的列表
拿出第一个元素,对其进行归位,即第一个元素最后的位置左侧都是比这个元素小的值,
右边的都是比这个元素大的值,这个元素就是一个分割线。
再以此元素的位置分割源列表为两个列表,不包括此元素,把左右两个列表,进行重复的归位,
而这个过程为递归实现,直到递归最后为1个元素,也就是最后的列表中只有一个元素,那么此时的下标
会出现左侧元素等于右侧元素而终止递归,最后返回的就是一个排序后的源列表。
"""
def sort_speed(li, left, right):
    if left < right:
        mid = mid_return(li, left, right)
        sort_speed(li, left, mid-1)
        sort_speed(li, mid+1, right)
    print(li)

def mid_return(li, left, right):
    tmp = li[left]
    while left < right:
        while left < right and li[right] >= tmp:
            right -= 1
        li[left] = li[right]
        while left < right and li[left] <= tmp:
            left += 1
        li[right] = li[left]
    li[left] = tmp
    return left

if __name__ == '__main__':
    li = [x for x in range(1,11)]
    print(li)
    random.shuffle(li)
    print(li)
    sort_speed(li, 0, len(li)-1)

最大公共子串问题

"""
求一个字符串数组中最大公共子串
"""
def islongsuf(li):
    lonsuf = ''
    minstr = min(li)
    for i in range(1, len(minstr)+1):
        for j in range(len(minstr)):
            tmp = minstr[j:j + i]
            if all(tmp in st for st in li):
                if len(tmp) > len(lonsuf):
                    lonsuf = tmp
    return lonsuf

if __name__ == '__main__':
    li = ['ahckili', 'ggckilkldas', 'asdjsackilsadsa']
    print(islongsuf(li))

排序算法之–归并排序

原理图
在这里插入图片描述

def mergesort(seq):
    """归并排序"""
    if len(seq) <= 1:
        return seq
    mid = len(seq) // 2  # 将列表分成更小的两个列表
    # 分别对左右两个列表进行处理,分别返回两个排序好的列表
    left = mergesort(seq[:mid])
    right = mergesort(seq[mid:])
    # 对排序好的两个列表合并,产生一个新的排序好的列表
    return merge(left, right)


def merge(left, right):
    """合并两个已排序好的列表,产生一个新的已排序好的列表"""
    result = []  # 新的已排序好的列表
    i = 0  # 下标
    j = 0
    # 对两个列表中的元素 两两对比。
    # 将最小的元素,放到result中,并对当前列表下标加1
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result += left[i:]
    result += right[j:]
    return result


seq = [2,1,7,5,10,14,11,61,20,22]
print('排序前:',seq)
result = mergesort(seq)
print('排序后:',result)

二叉树(Binary Tree即B树)

二叉树是每个节点最多拥有两个子节点,左子树和右子树是有顺序的不能任意颠倒。
在这里插入图片描述

二叉查找树

若任意节点的左子树不为空,则左子树上所有节点的值均小于它的根节点的值;
若任意节点的右子树不为空,则右子树上所有节点的值均大于或等于它的根节点的值;
任意节点的左、右子树分别为二叉查找树
在这里插入图片描述
二叉查找树(Binary Search Tree)也被称为二叉搜索树、有序二叉树(Ordered Binary Tree)或排序二叉树(Sorted Binary Tree)等

红黑树

红黑树(Red Black Tree)是一种自平衡二叉查找树,它最早被称之为“对称二叉 B 树”,它现在的名字源于 1978 年的一篇论文,之后便被称之为红黑树了。所谓的平衡树是指一种改进的二叉查找树,顾名思义平衡树就是将二叉查找树平衡均匀地分布,这样的好处就是可以减少二叉查找树的深度
一般情况下二叉查找树的查询复杂度取决于目标节点到树根的距离(即深度),当节点的深度普遍较大时,查询的平均复杂度就会上升,因此为了实现更高效的查询就有了平衡树

性质:
节点是红色或黑色;
根节点是黑色;
所有叶子都是黑色的空节点(NIL 节点);
每个红色节点必须有两个黑色的子节点,也就是说从每个叶子到根的所有路径上,不能有两个连续的红色节点;
从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑色节点

在这里插入图片描述

红黑树的优势
红黑树的优势在于它是一个平衡二叉查找树,对于普通的二叉查找树(非平衡二叉查找树)在极端情况下可能会退化为链表的结构,例如,当我们依次插入 3、4、5、6、7、8 这些数据时,二叉树会退化为链表结构。
当二叉查找树退化为链表数据结构后,再进行元素的添加、删除以及查询时,它的时间复杂度就会退化为 O(n);而如果使用红黑树的话,它就会将以上数据转化为平衡二叉查找树,这样就可以更加高效的添加、删除以及查询数据了,这就是红黑树的优势

它的添加、删除以及查询数据的时间复杂度为 O(logn)

B-树

B-树是一种自平衡的搜索树
在这里插入图片描述
1、多路,非二叉树
2、每个节点既保存索引,又保存数据
3、搜索时相当于二分查找

B+树

B-树的变种
在这里插入图片描述
1、多路非二叉
2、只有叶子节点保存数据
3、搜索时相当于二分查找
4、增加了相邻接点的指向指针。

那么B+树和B-树的区别是什么呢?
核心区别

一个是数据的保存位置,一个是相邻节点的指向

(1)B+树查询时间复杂度固定是logn,B-树查询复杂度最好是 O(1)。
(2)B+树相邻接点的指针可以大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和 data 在一起,则无法区间查找。
(3)B+树更适合外部存储,也就是磁盘存储。由于内节点无 data 域,每个节点能索引的范围更大更精确
(4)注意这个区别相当重要,是基于(1)(2)(3)的,B-树每个节点即保存数据又保存索引,所以磁盘IO的次数很少,B+树只有叶子节点保存,磁盘IO多,但是区间访问比较好

那么mongodb和mysql的区别也就可想而知??

MongoDB使用B-树,所有节点都有Data域,只要找到指定索引就可以进行访问,无疑单次查询平均快于Mysql
Mysql作为一个关系型数据库,数据的关联性是非常强的,区间访问是常见的一种情况,B+树由于数据全部存储在叶子节点,并且通过指针串在一起,这样就很容易的进行区间遍历甚至全部遍历

满二叉树(Full Binary Tree)

高度为h,由2^h-1个节点构成的二叉树称为满二叉树;
所有节点的度都要么为 0,要么为 2。且所有的叶子节点都在最后一层
在这里插入图片描述

完全二叉树

完全二叉树是由满二叉树而引出来的,若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数(即1~h-1层为一个满二叉树),第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。堆一般都是用完全二叉树来实现的。
在这里插入图片描述

堆(heap)

堆排序

而堆使用的是二叉堆。
二叉堆:
二叉堆是一种特殊的完全二叉树,可分为以下两种:

最大堆:根节点的值最大,任何一个父节点的值,都大于等于它左右孩子节点的值。
最小堆:根节点的值最小,任何一个父节点的值,都小于等于它左右孩子节点的值。
假设父节点的下标是p,那么对应左孩子下标就是2p+1,对应右孩子的下标就是2p+2

案例已最大二叉堆为例(由小到大)

mylist = [1, 3, 4, 5, 2, 6, 9, 7]

def heap_sink(heap, heap_size, parent_index):
    """最大堆-下沉算法"""
    tmp = heap[parent_index]
    child_index = 2 * parent_index + 1
    while child_index < heap_size:
        if child_index + 1 < heap_size and heap[child_index+1] > heap[child_index]:
            child_index += 1

        if tmp > heap[child_index]:
            break

        heap[parent_index] = heap[child_index]
        parent_index = child_index
        child_index = parent_index * 2 + 1
    heap[parent_index] = tmp



def heap_sort(mylist):
    """堆排序"""
    n = len(mylist)

    #创建最大堆
    for i in range((n-2)//2, -1, -1):
        heap_sink(mylist, n, i)
    #排序
    for j in range(n-1, 0, -1):
        mylist[0], mylist[j] = mylist[j], mylist[0]
        heap_sink(mylist, j, 0)

    return mylist
print(heap_sort(mylist)) # [1, 2, 3, 4, 5, 6, 7, 9]

构建最大堆和最小堆

class Solution:
    def __init__(self):
        self.__heap = []

    def parent(self, index):
        return (index - 1) // 2

    def left_child(self, index):
        return 2 * index + 1

    def right_child(self, index):
        return 2 * index + 2

    def heappush(self, item):
        self.__heap.append(item)
        self.sift_up(len(self.__heap)-1)

    def sift_up(self, index):
        while index > 0:
            parent = self.parent(index)

            if self.__heap[index] > self.__heap[parent]:
                self.__heap[index], self.__heap[parent] = self.__heap[parent], self.__heap[index]
                index = parent
            else:
                break

    def sift_down(self, index):
        while self.left_child(index) < len(self.__heap):
            left = self.left_child(index)
            right = self.right_child(index)
            max_node = right if right < len(self.__heap) and self.__heap[left] < self.__heap[right] else left
            if self.__heap[index] < self.__heap[max_node]:
                self.__heap[index], self.__heap[max_node] = self.__heap[max_node], self.__heap[index]
                index = max_node
            else:
                break

    def heappop(self):
        if len(self.__heap) == 0:
            return None
        self.__heap[0], self.__heap[-1] = self.__heap[-1], self.__heap[0]
        data = self.__heap.pop()
        self.sift_down(0)
        return data

    @property
    def show_heap(self):
        return self.__heap


# 建堆
sort_list = []
local_heap = Solution()
for i in range(1, 11):
    local_heap.heappush(i)
print(local_heap.show_heap)
for i in range(len(local_heap.show_heap)):
    sort_list.append(local_heap.heappop())
    print(local_heap.show_heap)
print("asdas", sort_list)
print(local_heap.show_heap)
"""
[10, 9, 6, 7, 8, 2, 5, 1, 4, 3]
[9, 8, 6, 7, 3, 2, 5, 1, 4]
[8, 7, 6, 4, 3, 2, 5, 1]
[7, 4, 6, 1, 3, 2, 5]
[6, 4, 5, 1, 3, 2]
[5, 4, 2, 1, 3]
[4, 3, 2, 1]
[3, 1, 2]
[2, 1]
[1]
[]
asdas [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[]
"""

二叉树实现及查找原理

在这里插入图片描述

“”“
此类创建一个二叉树
”“”
class ErChaShu:

    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None


a = ErChaShu('A')
b = ErChaShu('B')
c = ErChaShu('C')
d = ErChaShu('D')
e = ErChaShu('E')
f = ErChaShu('F')
g = ErChaShu('G')

e.lchild = a
e.rchild = g
a.rchild = c
c.lchild = b
c.rchild = d
g.rchild = f

root = e



"""
以下三种遍历都是深度遍历

先序遍历  根--》左--》右
"""
def pre_find(root):
    if root:
        print(root.data, end='')
        pre_find(root.lchild)
        pre_find(root.rchild)

"""
此方法是使用栈(先进后出)实现深度遍历的前序遍历
核心 添加根-右子树-左子树
"""

def pre1_find(root):
    if not root:
        return
    q = []
    q.append(root)

    while True:
        if not q:
            return
        current = q.pop()
        print(current.data, end='')
        if current.rchild:
            q.append(current.rchild)
        if current.lchild:
            q.append(current.lchild)

"""
中序遍历 左--》根--》右
"""
def mi_find(root):
    if root:
        mi_find(root.lchild)
        print(root.data, end='')
        mi_find(root.rchild)


"""
后序遍历 左--》右--》根
"""
def fi_find(root):
    if root:
        fi_find(root.lchild)
        fi_find(root.rchild)
        print(root.data, end='')


"""
广度优先遍历:
利用队列先进先出,将根、左、右存入,按照队列的先进先出实现层次遍历
"""

def BfS(root):
    """广度优先遍历"""
    if not root:
        return
    q = []
    print(root.data)
    q.append(root)

    while True:
        if not q:
            return
        curentNode = q.pop(0)
        print(curentNode.data, end='')
        if curentNode.lchild:
            q.append(curentNode.lchild)
        if curentNode.rchild:
            q.append(curentNode.rchild)

BfS(root)

查找算法-二分查找

前提:
每次能够排除掉一半的数据,查找的效率非常高,但是局限性比较大。
必须是有序序列才可以使用二分查找。

def binary_search(lis, left, right, num):

    if left > right: #递归结束条件
        return -1
    mid = (left + right) // 2
    if num < lis[mid]:
        right = mid -1
    elif num > lis[mid]:
        left = mid + 1
    else:
        return mid
    return binary_search(lis, left, right, num)

lis = [11, 32, 51, 21, 42, 9, 5, 6, 7, 8]
print(lis)
lis.sort()
num = 9 # 要查找的数
res = binary_search(lis, 0, len(lis)-1,num) # 返回值是索引

在这里插入图片描述

C程序的元素分配

栈区(stack):由编译器自动分配和释放,存放函数的参数值,局部变量的等临时的值.

堆区(heap):一般由程序员分配释放(动态内存申请与释放),若程序员不释放,程序结束时可能由操作系统回收

全局区(静态区) (static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区城, 该区域在程序结束后由操作系统释放

常量区:字符串常量和其他常量的存储位置,程序结束后由操作系统释放

程序代码区:存放函教体的二进制代码

数据结构

单链表/双链表

class Node:
    """节点类"""
    def __init__(self, elem):
        self.elem = elem
        self.next = None
        self.prev = None


class SingleLinkList(object):
    def __init__(self, node=None):
        self._head = node

    # 从尾部添加
    def append(self, data):
        node = Node(data)
        if self._head is None:
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            cur.next = node

    # 从头部添加
    def add(self, data):
        node = Node(data)
        if self._head is None:
            self._head = node
        else:
            next_node = self._head
            self._head = node
            self._head.next = next_node

    # 遍历链表
    def show(self):
        if not self._head:
            return []
        result = []
        cur_node = self._head
        while cur_node:
            result.append(cur_node.elem)
            cur_node = cur_node.next
        return result

    # 插入元素
    def insert(self, data, index):
        n = Node(data)
        elem_list = self.show()
        if index < 0:
            self.add(data)
        elif index >= len(elem_list):
            self.append(data)
        else:
            offset = 0
            cur = self._head
            while True:
                if offset == (index - 1):
                    cur_next = cur.next
                    n.next = cur_next
                    cur.next = n
                    break
                cur = cur.next
                offset += 1

    # 删除元素
    def remove(self, index):
        if self.is_empty():
            return

        elem_list = self.show()
        if 0 > index or index >= len(elem_list):
            return

        offset = 0
        cur = self._head

        # 删除头元素
        if index == 0:
            self._head = cur.next
            return
        # 删除尾部元素
        if index == len(elem_list) - 1:
            offset = 0
            while cur:
                if offset == len(elem_list) - 2:
                    cur.next = None
                    break
                cur = cur.next
                offset += 1
            return

        while True:
            if offset == (index - 1):
                cur_next = cur.next.next
                cur.next = cur_next
                break
            cur = cur.next
            offset += 1
        return

    # 是否为空
    def is_empty(self):
        if not self._head:
            return True
        else:
            return False


n = SingleLinkList()
n.add(1)
n.add(2)
n.add(3)
n.add(4)
n.append(10)
n.append(20)
n.insert(30, 2)
n.remove(6)
print(n.show())


# 双向链表
class DoubleLinkList(SingleLinkList):

    # 从头部添加
    def add(self, data):
        node = Node(data)
        if self._head is None:
            self._head = node
        else:
            next_node = self._head
            self._head = node
            self._head.next = next_node
            next_node.prev = self._head

    # 从尾部添加
    def append(self, data):
        node = Node(data)
        if self._head is None:
            self._head = node
        else:
            cur = self._head
            while cur.next != None:
                cur = cur.next
            cur.next = node
            node.prev = cur


double_list = DoubleLinkList()
double_list.add(1)
double_list.add(2)

print(double_list.show())

动态规划

爬楼梯问题

# 动态规划--斐波那契数列
def fei_list_code(n):
    i, j = 1, 1
    for x in range(1, n):
        i, j = j, i+j
    return i


def fbi(n):
    if n == 1 or n == 2:
        return 1
    return fbi(n-1) + fbi(n-2)



print(fbi(3))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值