Python基础学习笔记 —— 数据结构与算法

news2024/11/26 9:32:19

数据结构与算法

  • 1 数据结构基础
    • 1.1 数组
    • 1.2 链表
    • 1.3 队列
    • 1.4 栈
    • 1.5 二叉树
  • 2 排序算法
    • 2.1 冒泡排序
    • 2.2 快速排序
    • 2.3 (简单)选择排序
    • 2.4 堆排序
    • 2.5 (直接)插入排序
  • 3 查找
    • 3.1 二分查找

1 数据结构基础

本章所需相关基础知识:

  • Python基础学习笔记(二)—— 数据类型及操作
  • Python基础学习笔记(六)—— 面向对象编程(1)

1.1 数组

1. 数组的基本结构

数组是最常见的一种数据结构,其由有限个类型相同的变量按照一定的顺序组合构成,在Python中常常利用列表(list)来表示数组。Python定义数组的时候与C/C++中定义数组时的区别在于定义时无序指定长度,可以动态增长,不断向后追加元素,一般不会出现数组溢出的状况,为编程者带来了极大的自由度。

# 一维数组
arr1 = [1, 2, 3, 4]
print(arr1)  # [1, 2, 3, 4]
print(arr1[0])  # 1

# 二维数组
arr2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
print(arr2)  # [[1, 2, 3, 4], [5, 6, 7, 8]]
print(arr2[0][3])  # 4
# 一般通过如下方式定义一个二维数组
arr3 = [[i for i in range(4)] for j in range(3)]
print(arr3)  # [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]

2. 数组的基本操作

# 定义
arr = [1, 2, 3, 4, 5, 1]

# 增加
# arr.append(6)
# print(arr) # [1, 2, 3, 4, 5, 1, 6]

# 删除(利用pop(),remove(),del()方法删除元素)
# 1. pop([索引]) 删除指定索引对应的元素,默认删除数组最后一个元素,并返回该值
# arr.pop()
# arr.pop(1)
# 2. remove(元素值) 删除数组里某个值的第一个匹配项
# arr.remove(1)
# 3. del() 按照索引删除元素
# del(arr[2])
# del arr[2]

# 插入
# insert(插入的索引位置,插入的元素)
# arr.insert(0, 100)

# 查找
# 1. 想确定数组中是否含有某一个元素
# if 200 in arr:
#     print("True")
# 2. 想确定某个元素的索引,index(元素值) 查找数组中该元素第一次出现的索引
# arr.index(1)

# 修改
# 通过索引直接访问重新赋值即可
# arr[0] = 9

# 反转
# reverse()方法反转列表,直接对数组进行操作,没有产生额外的空间
# arr.reverse()

# 排序
# sort(key=None,reverse=False)默认升序,修改reverse=True则为降序
# arr.sort()
# arr.sort(reverse=True)

# 清空
# 对数组进行清空,输出[]
# arr.clear()

# 截取
# 按步长截取,顾头不顾尾
# 数组名[起始索引(不写则默认包含数组开始的所有元素),终止索引(不写则默认包含到数组结束的所有元素),步长(默认为1)]
# print(arr[::2])  # [1, 3, 5]
# print(arr[::-1])  # [1, 5, 4, 3, 2, 1]
# print(arr[:-1])  # [1, 2, 3, 4, 5]

1.2 链表

1. 链表的基本结构

链表主要包括单向链表和双向链表,这是一种无须在内存中顺序存储即可保持数据之间逻辑关系的数据结构。

链表是由一个个节点(Node)连接而成的,每个节点都是包含数据域(Data)和指针域(Next)的基本单元。其基本元素如下:

  • 链表节点:每个节点分为两部分,即数据域和指针域
    • 数据域:数据域内一般存储的是整型、浮点型等数字类型
    • 指针域:指针域内一般存储的是下一个节点所在的内存空间地址
  • 头节点:指向链表的第一个节点
  • 尾节点:指向链表的最后一个节点
  • None:链表的最后一个节点的指针域,为空

单链表

单链表的每个节点的指针域只指向下一个节点,整个链表是无环的

在这里插入图片描述

双向链表

在这里插入图片描述

单向循环链表

在这里插入图片描述

相比于数组,在链表中执行插入、删除等操作可以使得操作效率大大提高。

以单链表为例,在数组内如想要删除或者插入元素到某一位置,该位置之后的所有元素都需要象前或者向后移动,这样一来,时间复杂度就与数组的长度有关,为O(n);但是在单链表中,仅仅需要通过改变所要删除或者插入位置前后节点的指针域即可,时间复杂度为O(1)。

2. 单链表的实现与基本操作

# 链表结点
class Node(object):
    def __init__(self, item):
        self.item = item
        self.next = None


# 单链表
class SingleLink(object):
    # 选择该初始化方法,调用时使用 SingleLink(node)
    def __init__(self, node=None):
        self.head = node

    # 选择该初始化方法,调用时就不能使用上面的 SingleLink(node),初始化只能通过append添加节点
    # def __init__(self):
    #     self.head = None

    # 判断单链表是否为空
    def is_empty(self):
        if self.head is None:
            return True
        else:
            return False

    # 获取链表长度
    def length(self):
        cur = self.head
        count = 0
        while cur is not None:
            cur = cur.next
            count += 1
        return count

    # 遍历链表
    def travel(self):
        cur = self.head
        while cur is not None:
            print(cur.item)
            cur = cur.next

    # 链表头部增加结点
    def add(self, item):
        node = SingNode(item)
        node.next = self.head
        self.head = node

    # 链表尾部增加结点
    """
    注意:如果链表为空链表,cur是没有next的,只需self.head=node
    """

    def append(self, item):
        node = SingNode(item)
        if self.is_empty():
            self.head = node
        else:
            cur = self.head
            while cur.next is not None:
                cur = cur.next
            cur.next = node

    # 链表指定位置增加结点
    def insert(self, pos, item):
        if pos == 0:
            self.add(item)
        elif pos >= self.length():
            self.append(item)
        else:
            node = SingNode(item)
            cur = self.head
            count = 0
            while count < pos - 1:
                cur = cur.next
                count += 1
            node.next = cur.next
            cur.next = node

    # 删除结点
    def remove(self, item):
        cur = self.head
        pre = None
        while cur is not None:
            # 找到了要删除的元素
            if cur.item == item:
                # 如果要删除的位置在头部
                if cur == self.head:
                    self.head = cur.next
                # 要删除的位置不在头部
                else:
                    pre.next = cur.next
                return  # 删除元素后及时退出循环
            # 没有找到要删除的元素
            else:
                pre = cur
                cur = cur.next

    # 查找结点
    def search(self, item):
        cur = self.head
        while cur is not None:
            if cur.item == item:
                return True
            cur = cur.next
        return False

1.3 队列

1. 队列的基本结构

队列最基本的特点就是先进先出,在队列尾部加入新元素,在队列头部删除元素,分为双端队列和一般的单端队列。

队列的作用:对于任务处理类的系统,即先把用户发起的任务请求接收过来存到队列中,然后后端开启多个应用程序从队列中取任务进行处理,队列起到了 缓冲压力 的作用

2. 队列的实现与基本操作

利用列表来简单地模拟队列

class Queue(object):
    def __init__(self):
        self.items = []

    # 入队
    def enqueue(self, item):
        self.items.append(item)

    # 出队
    def dequeue(self):
        self.items.pop(0)

    # 队列的大小
    def size(self):
        return len(self.items)

    # 判断队列是否为空
    def is_empty(self):
        return self.items == []

对于队列这种数据结构,Python的 queue 类模块中提供了一种先进先出的队列模型 Queue,可以限制队列的长度也可以不限制,在创建队列时利用 Queue(maxsize=0),maxsize小于等于0表示不限制,否则表示限制。

我们在编程的过程中也可以通过调用现有类来实现队列

from queue import Queue

# 队列的定义
q = Queue(maxsize=0)

# put() 在队列尾部添加元素
q.put(1)
q.put(2)
# print(q) # <queue.Queue object at 0x0000020095EE82B0>
# print(q.queue) # deque([1, 2])

# get() 在队列头部取出元素,返回队列头部元素
q.get()
print(q.queue)  # deque([2])

# empty() 判断队列是否为空
print(q.empty())  # False

# full(0 判断队列是否达到最大长度限制
print(q.full())  # False

# qsize() 队列当前的长度
print(q.qsize())  # 1

3. 双端队列的实现与基本操作

双端队列(deque,全名double-ended queue ), 是一种具有队列和栈的性质的数据结构
双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。双端队列可以在队列任意一端入队和出队。

class deque(object):
    def __init__(self):
        self.items = []

    # 判断是否为空
    def is_empty(self):
        return self.items == []

    # 队列的大小
    def size(self):
        return len(self.items)

    # 头部添加数据
    def add_front(self, item):
        self.items.insert(0, item)

    # 尾部添加数据
    def add_rear(self, item):
        self.items.append(item)

    # 头部删除数据
    def remove_front(self):
        self.items.pop(0)

    # 尾部删除数据
    def remove(self):
        self.items.pop()

1.4 栈

1. 栈的基本结构

栈最突出的特点是先进后出,其插入、删除操作均在栈顶进行。栈一般包括入栈、出栈操作,并且有一个顶指针(top)用于指示栈顶的位置

2. 栈的实现与基本操作

class Stack(object):
    def __init__(self):
        self.items = []  

    # 进栈
    def push(self, item):
        self.items.append(item)

    # 出栈
    def pop(self):
        self.items.pop()

    # 遍历
    def travel(self):
        for i in self.items:
            print(i)

    # 栈的大小
    def size(self):
        return len(self.items)

    # 栈是否为空
    def is_empty(self):
        return self.items == []
        # return len(self.items) == 0

    # 返回栈顶元素
    def peek(self):
    	if self.is_empty():
    		return "栈空"
        return self.items[self.size()-1]
        # return self.items[-1]

1.5 二叉树

1. 树

树是一种数据结构,它是由 n 个有限节点组成的一个具有层次关系的集合。

树的基本性质如下:

在这里插入图片描述

2. 二叉树的基本结构

二叉树则是每个节点最多有两个子树的树结构,通常子树被称作“左子树”和“右子树”。

二叉树的一般性质:

  • 二叉树是有序的(左右子树不能颠倒)
  • 二叉树的第 k 层上的节点数目最多为 2 k − 1 2^{k-1} 2k1
  • 深度为 h 的二叉树最多有 2 h − 1 2^h-1 2h1 个节点
  • 设非空二叉树中度为0、1 和 2 的结点个数分别为 n 0 n_0 n0 n 1 n_1 n1 n 2 n_2 n2,则 n 0 = n 2 + 1 n_0 = n_2+1 n0=n2+1
    (叶子结点比二分支结点多一个)

其他常见的二叉树:

在这里插入图片描述

在这里插入图片描述

二叉树通常以链式存储

3. 二叉树的实现与基本操作

# 定义节点类
class Node(object):
    def __init__(self, item):
        self.item = item
        self.lchild = None
        self.rchild = None


# 定义二叉树
class BinaryTree(object):
    def __init__(self, node=None):
        self.root = node

    """
    思路分析:首先在队列中插入根节点,取出该节点,再判断该节点的左右子树是否为空,
    左子节点不空,将其入队,右子节点不空,将其入队,
    再分别判断左右节点的左右子节点是否为空,
    循环往复,直到发现某个子节点为空,即把新节点添加进来
    """

    # 添加节点
    def add(self, item):
        node = Node(item)
        # 二叉树为空
        if self.root is None:
            self.root = node
            return

        # 二叉树不空
        queue = []
        queue.append(self.root)
        while True:
            # 从队头取出数据
            node1 = queue.pop(0)
            # 判断左节点是否为空
            if node1.lchild is None:
                node1.lchild = node
                return
            else:
                queue.append(node1.lchild)
            # 判断右节点是否为空
            if node1.rchild is None:
                node1.rchild = node
                return
            else:
                queue.append(node1.rchild)

    # 广度优先遍历,也叫层次遍历
    def breadth(self):
        if self.root is None:
            return

        queue = []
        queue.append(self.root)
        while len(queue) > 0:
            # 取出数据
            node = queue.pop(0)
            print(node.item, end=" ")

            # 判断左右子节点是否为空
            if node.lchild is not None:
                queue.append(node.lchild)
            if node.rchild is not None:
                queue.append(node.rchild)

    # 深度优先遍历
    # 先序遍历(根左右)
    def preorder_travel(self, root):
        if root is not None:
            print(root.item, end="")
            self.preorder_travel(root.lchild)
            self.preorder_travel(root.rchild)

    # 中序遍历(左根右)
    def inorder_travel(self, root):
        if root is not None:
            self.inorder_travel(root.lchild)
            print(root.item, end="")
            self.inorder_travel(root.rchild)

    # 后序遍历(左右根)
    def postorder_travel(self, root):
        if root is not None:
            self.postorder_travel(root.lchild)
            self.postorder_travel(root.rchild)
            print(root.item, end="")

注意:

  • 广度优先遍历基于队列
  • 深度优先遍历基于栈

试试 LeetCode 相关题目吧

  • 102. 二叉树的层序遍历
  • 144.二叉树的前序遍历
  • 94. 二叉树的中序遍历
  • 145. 二叉树的后序遍历

4. 由遍历结果反推二叉树结构

在这里插入图片描述

2 排序算法

算法的稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变则称这种排序算法是稳定的,否则称为不稳定的

  • 不稳定的排序算法:选择排序、快速排序、希尔排序、堆排序
  • 稳定的排序算法:冒泡排序、插入排序、归并排序、基数排序

2.1 冒泡排序

对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,依次对所有的数据进行操作,直至所有数据按要求完成排序

如果有n个数据进行排序,总共需要比较 n-1 次

每一次比较完毕,下一次的比较就会少一个数据参与

在这里插入图片描述

def bubble_sort(lis):
    n = len(lis)
    # 控制比较的轮数
    for j in range(n - 1):
        count = 0
        # 控制每一轮的比较次数
        # -1是为了让数组不要越界
        # -j是每一轮结束之后, 我们就会少比一个数字
        for i in range(n - 1 - j):
            if lis[i] > lis[i + 1]:
                lis[i], lis[i + 1] = lis[i + 1], lis[i]
                count += 1
        # 算法优化
        # 如果遍历一遍发现没有数字交换,退出循环,说明数列是有序的
        if count == 0:
            break


if __name__ == "__main__":
    lis = [2, 7, 3, 6, 9, 4]
    bubble_sort(lis)
    print(lis)

总结:

  • 冒泡排序是稳定的
  • 最坏时间复杂度为 O ( n 2 ) O(n^2) O(n2)
  • 最优时间复杂度为 O ( n ) O(n) O(n),遍历一遍发现没有任何元素发生了位置交换终止排序

2.2 快速排序

快速排序算法中,每一次递归时以第一个数为基准数 ,找到数组中所有比基准数小的。再找到所有比基准数大的。小的全部放左边,大的全部放右边,确定基准数的正确位置。

def quick_sort(lis, left, right):
    # 递归的结束条件:left > right
    if left > right:
        return

    # 存储临时变量,left0始终为0,right0始终为len(lis)-1
    left0 = left
    right0 = right

    # 基准值
    base = lis[left0]

    # left != right
    while left != right:
        # 从右边开始找寻小于mid的值
        while lis[right] >= base and left < right:
            right -= 1

        # 从左边开始找寻大于mid的值
        while lis[left] <= base and left < right:
            left += 1

        # 交换两个数的值
        lis[left], lis[right] = lis[right], lis[left]

    # left=right
    # 基准数归位
    lis[left0], lis[left] = lis[left], lis[left0]

    # 递归操作
    quick_sort(lis, left0, left - 1)
    quick_sort(lis, left + 1, right0)  # quick_sort(lis, left + 1, right0)


if __name__ == '__main__':
    lis = [1, 2, 100, 50, 1000, 0, 10, 1]
    quick_sort(lis, 0, len(lis) - 1)
    print(lis)

总结:

  • 快速排序算法不稳定
  • 最好的时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n),初始序列大小均匀,每一次选择的基准值将待排序的序列划分为均匀的两部分,递归深度最小,算法效率最高
  • 最坏的时间复杂度: O ( n 2 ) O(n^2) O(n2),初始序列有序或逆序,每次选择的基准值都是靠边的元素,递归深度最大,算法效率最低

2.3 (简单)选择排序

第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾,以此类推,直到全部待排序的数据元素的个数为零。

在这里插入图片描述

def select_sort(lis):
    n = len(lis)
    # 控制比较的轮数
    for j in range(n - 1):
        # 假定最小值的下标
        min_index = j
        # 控制每一轮的比较次数
        for i in range(j + 1, n):
        	# 进行比较获得最小值下标
            if lis[min_index] > lis[i]:
            	min_index = i
        # 如果假定的最小值下标发生了变化,那么就进行交换
        if min_index != j:
            lis[min_index], lis[j] = lis[j], lis[min_index]


if __name__ == "__main__":
    lis = [2, 7, 3, 6, 9, 4]
    select_sort(lis)
    print(lis)

总结:

  • 选择排序是不稳定的
  • 最坏时间复杂度为O(n^2)
  • 最优时间复杂度为O(n^2)

2.4 堆排序


堆排序是不稳定的

2.5 (直接)插入排序

插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序

插入算法把要排序的数组分成两部分:

  • 第一部分是有序的数字(这里可以默认数组第一个数字为有序的第一部分)
  • 第二部分为无序的数字(这里除了第一个数字以外剩余的数字可以认为是无序的第二部分)
def insert_sort(lis):
    n = len(lis)
    # 控制比较的轮数,即无序数据的个数,一个数肯定是有序的,不用比较
    for j in range(1, n):
        # 控制每一轮的比较次数
        # i取值范围[j,j-1,j-2,j-3,,,1]
        # 取出无序部分的首个,在有序部分从后向前比较,插入到合适的位置
        for i in range(j, 0, -1):
            # 找到合适的位置安放无序数据
            if lis[i] < lis[i - 1]:
                lis[i], lis[i - 1] = lis[i - 1], lis[i]
            else:
                break


if __name__ == "__main__":
    lis = [2, 7, 3, 6, 9, 4]
    insert_sort(lis)
    print(lis)

总结:

  • 直接插入排序是稳定的
  • 最坏时间复杂度为O(n^2),本身倒序
  • 最优时间复杂度为O(n),本身有序,每一轮只需比较一次

3 查找

3.1 二分查找

二分查找的适用前提:必须有序

非递归方法

def binary_search(lis, num):
    left = 0
    right = len(arr) - 1
    while left <= right:
        mid = (left + right) // 2
        if num > lis[mid]:
            left = mid + 1
        elif num < lis[mid]:
            right = mid - 1
        else:  # num == arr[mid]
            return mid
    return -1


if __name__ == "__main__":
    lis = [1, 3, 5, 7, 9, 10]
    print(binary_search(lis, 5))  # 2
    print(binary_search(lis, 8))  # -1

递归方法


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/345480.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第七届蓝桥杯省赛——1有奖猜谜

题目&#xff1a; 小明很喜欢猜谜语。 最近&#xff0c;他被邀请参加了X星球的猜谜活动。 每位选手开始的时候都被发给777个电子币。 规则是&#xff1a;猜对了&#xff0c;手里的电子币数目翻倍&#xff0c; 猜错了&#xff0c;扣除555个电子币, 扣完为止。 小明一共猜了15…

入门深度学习——基于全连接神经网络的手写数字识别案例(python代码实现)

入门深度学习——基于全连接神经网络的手写数字识别案例&#xff08;python代码实现&#xff09; 一、网络构建 1.1 问题导入 如图所示&#xff0c;数字五的图片作为输入&#xff0c;layer01层为输入层&#xff0c;layer02层为隐藏层&#xff0c;找出每列最大值对应索引为输…

云原生周刊 | 开源领导者应该如何应对碎片化挑战?

Linux Fundation 发布了一份关于开源开发中的碎片化问题的报告《实现全球协作&#xff1a;开源领导者如何应对碎片化挑战》&#xff0c;该报告由华为在美国的研发部门 Futurewei 赞助。报告指出&#xff0c;虽然开源社区越来越国际化&#xff0c;但美国对开源共享和开发进行了过…

源码项目中常见设计模式及实现

原文https://mp.weixin.qq.com/s/K8yesHkTCerRhS0HfB0LeA 单例模式 单例模式是指一个类在一个进程中只有一个实例对象&#xff08;但也不一定&#xff0c;比如Spring中的Bean的单例是指在一个容器中是单例的&#xff09; 单例模式创建分为饿汉式和懒汉式&#xff0c;总共大概…

Linux内核驱动开发(一)

Linux内核初探 linux操作系统历史 开发模式 git 分布式管理git clone 获取git push 提交git pull 更新 邮件组 mailing list patch 内核代码组成 Makfile arch 体系系统架构相关 block 块设备 crypto 加密算法 drivers 驱动&#xff08;85%&#xff09; atm 通信bluet…

MAC文件误删怎么办?mac数据恢复,亲测很好用的方法

电脑文件误删&#xff0c;应该很多人都经历过。之前分享了很多关于Windows电脑文件误删如何恢复的方法&#xff0c;那么MAC电脑文件误删该怎么办&#xff1f;有什么好方法可以使得mac数据恢复回来吗&#xff1f;下面就给大家分享一些亲测好用的方法&#xff01; 一、MAC电脑的文…

使用Proxifier+burp抓包总结

一、微信小程序&网页抓包 1. Proxifier简介 Proxifier是一款功能非常强大的socks5客户端&#xff0c;可以让不支持通过代理服务器工作的网络程序能通过HTTPS或SOCKS代理或代理链。 2. 使用Proxifier代理抓包 原理&#xff1a;让微信相关流量先走127.0.0.1:80到burp。具体…

Final Cut Pro 10.6.5

软件介绍Final Cut Pro 10.6.5 已通过小编安装运行测试 100%可以使用。Final Cut Pro 10.6.5 破解版启用了全新的矩形图标&#xff0c;与最新的macOS Ventura设计风格统一&#xff0c;支持最新的macOS 13 文图拉系统&#xff0c;支持Apple M1/M2芯片。经过完整而彻底的重新设计…

数据结构之单链表

一、链表的组成 链表是由一个一个的节点组成的&#xff0c;节点又是一个一个的对象&#xff0c; 相邻的节点之间产生联系&#xff0c;形成一条链表。 例子&#xff1a;假如现在有两个人&#xff0c;A和B&#xff0c;A保存了B的联系方式&#xff0c;这俩人之间就有了联系。 A和…

HashMap底层实现原理概述

原文https://blog.csdn.net/fedorafrog/article/details/115478407 hashMap结构 常见问题 在理解了HashMap的整体架构的基础上&#xff0c;我们可以试着回答一下下面的几个问题&#xff0c;如果对其中的某几个问题还有疑惑&#xff0c;那就说明我们还需要深入代码&#xff0c…

ubuntu 20.04 安装 flameshot截图工具

ubuntu 20.04 安装 flameshot截图工具安装命令使用命令设置快捷键效果图安装命令 sudo apt-get install flameshot安装日志 $ sudo apt-get install flameshot [sudo] password for huifeimao: Reading package lists… Done Building dependency tree Reading state informat…

【零基础入门前端系列】—表格(五)

【零基础入门前端系列】—表格&#xff08;五&#xff09; 一、表格 表格在数据展示方面非常简单&#xff0c;并且表现优秀&#xff0c;通过与CSS的结合&#xff0c;可以让数据变得更加美观和整齐。 单元格的特点&#xff1a;同行等高、同列等宽。 表格的基本语法&#xff1…

性能测试之tomcat+nginx负载均衡

nginx tomcat 配置准备工作&#xff1a;两个tomcat 执行命令 cp -r apache-tomcat-8.5.56 apache-tomcat-8.5.56_2修改被复制的tomcat2下conf的server.xml 的端口号&#xff0c;不能与tomcat1的端口号重复&#xff0c;不然会启动报错 ,一台电脑上想要启动多个tomcat&#xff0c…

自定义bean 加载到spring IOC容器中

自定义bean加载到spring容器中的两种方式&#xff1a; 1.在类上添加注解Controller、RestController&#xff08;本质是Controller&#xff09;、Service、Repository、Component2.使用Configuration和Bean 这篇文章主要介绍第二种方式原理&#xff08;因为在实际使用中&#…

SteaLinG:一款针对社工的开源安全渗透测试框架

关于SteaLinG SteaLinG是一款功能强大的开源渗透测试框架&#xff0c;该框架专为社会工程学研究人员设计&#xff0c;可以帮助广大研究人员或组织内的安全专家测试目标设备的安全性。该工具基于Python开发&#xff0c;因此具备良好的跨平台特性。在使用时&#xff0c;我们只需…

2023软考纸质证书领取通知来了!

不少同学都在关注2022下半年软考证书领取时间&#xff0c;截止至目前&#xff0c;上海、湖北、江苏、南京、安徽、山东、浙江、宁波、江西、贵州、云南、辽宁、大连、吉林、广西地区的纸质证书可以领取了。将持续更新2022下半年软考纸质证书领取时间&#xff0c;请同学们在证书…

信息安全保障

信息安全保障信息安全保障基础信息安全保障背景信息安全保障概念与模型基于时间的PDR模型PPDR模型&#xff08;时间&#xff09;IATF模型--深度防御保障模型&#xff08;空间&#xff09;信息安全保障实践我国信息安全保障实践各国信息安全保障我国信息安全保障体系信息安全保障…

SpringColud第四讲 Nacos的Windows安装方式和Linux的安装方式

在Nacos的GitHub页面&#xff0c;提供有下载链接&#xff0c;可以下载编译好的Nacos服务端或者源代码&#xff1a; 目录 1.Windows安装Nacos 1.1.下载 1.2.解压 1.3.修改相关配置&#xff1a; 1.4.启动&#xff1a; 1.5.登录&#xff1a; 2.Linux的安装方式Nacos 2.1.…

python cartopy手动导入地图数据绘制底图/python地图上绘制散点图:Downloading:warnings/散点图添加图里标签

……开学回所&#xff0c;打开电脑spyder一看一脸懵逼&#xff0c;简直不敢相信这些都是我自己用过的代码&#xff0c;想把以前的自己喊过来科研了&#xff08;&#xff09; 废话少说&#xff0c;最近写小综述论文&#xff0c;需要绘制一个地图底图&#xff0b;散点图&#xff…

Cortex-M0存储器系统

目录1.概述2.存储器映射3.程序存储器、Boot Loader和存储器重映射4.数据存储器5.支持小端和大端数据类型数据对齐访问非法地址多寄存器加载和存储指令的使用6.存储器属性1.概述 Cortex-M0处理器具有32位系统总线接口&#xff0c;以及32位地址线&#xff08;4GB的地址空间&…