左神算法基础巩固--1

文章目录

    • 时间复杂度
      • 常数时间的操作
      • 时间复杂度的定义
      • 时间复杂度的作用
      • 剖析递归行为和递归行为时间复杂度的估算
    • 排序
      • 选择排序
      • 冒泡排序
      • 插入排序
      • 归并排序
        • 小和问题
          • 问题描述
          • 解题思路
      • 快速排序
        • 荷兰国旗问题
          • 问题描述
      • 堆排序
        • 堆结构
          • 大根堆
          • 小根堆
      • 桶排序
    • 二分
      • 二分搜索
    • ^的运用
      • 不用额外空间交换两个数的值
      • 数组中存在一个数有奇数次,其他数均出现偶数次,找到那个出现奇数次的数
    • 对数器
      • 对数器的概念和使用

时间复杂度

常数时间的操作

一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。

下面这段代码就是一个常数操作的代码,他仅仅只是从一个数组中取出一个数,跟数组的规模没有任何关系,无论数组是几亿甚至是几十亿也好,执行这段代码所需的时间都不会发生改变。
在这里插入图片描述
但下面这段代码不同,下面这段代码是从一个链表中取出对应位置的数(List list = newLinkedList();),在这段代码中拿到对应的值需要先遍历一遍链表,这一操作与链表的规模有关,故链表的规模会影响其执行这段代码的时间。
在这里插入图片描述

时间复杂度的定义

时间复杂度为一个算法流程中,常数操作数量的一个指标。常用O(读作big O)来表示。具体来说,先要对一个算法流程非常熟悉,然后去写出这个算法流程中,发生了多少常数操作,进而总结出常数操作数量的表达式。在表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,剩下的部分如果为f(N),那么时间复杂度为O(f(N))。

时间复杂度的作用

评价一个算法流程的好坏,先看时间复杂度的指标,然后再分析不同数据样本下的实际运行时间,也就是“常数项时间”。

剖析递归行为和递归行为时间复杂度的估算

用递归方法找一个数组中的最大值,系统上到底是怎么做的?
master公式的使用
T(N) = a*T(N/b) + O(N^d)

  1. log(b,a) > d -> 复杂度为O(N^log(b,a))
  2. log(b,a) = d -> 复杂度为O(N^d * logN)
  3. log(b,a) < d -> 复杂度为O(N^d)
    补充阅读:www.gocalf.com/blog/algorithm-complexity-and-master- theorem.html
    以下列代码为例
public static int getMax(int[] arr) {
		return process(arr, 0, arr.length - 1);
	}

	public static int process(int[] arr, int L, int R) {
		if (L == R) {
			return arr[L];
		}
		int mid = L + ((R - L) &gt;&gt; 1);
		int leftMax = process(arr, L, mid);
		int rightMax = process(arr, mid + 1, R);
		return Math.max(leftMax, rightMax);
	}

在这段代码中 a为2,因为在一次递归中调用了两次process函数 ,b为2,因为在一次递归中将问题的规模缩小为原来的1/2,d为0,因为除去一次递归中除去调用过程外的时间复杂度为O(1)算出d为1

排序

选择排序

选择排序的算法思想是指,将在数组中一开始选定一个数将这个数初始定义为这个数组的最小值,然后遍历这个数组让这个数与数组中所有数进行比较找出真正的最小值并将其与第一个位置交换位置。之后再找到次小值将其与第二个数交换位置,不断重复直到将这个数组的每一个位置都重新赋值。

public static void selectionSort(int[] arr) {
        // 数组过滤 (如果数组不存在或数组数组只有一个元素便不需要排序)
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 0; i < arr.length - 1; i++) {
			int minIndex = i;// 选定一个数
			for (int j = i + 1; j < arr.length; j++) {
				minIndex = arr[j] < arr[minIndex] ? j : minIndex;//将这个数与数组中的其他数进行比较,找到真正的最小值对应的下标
			}
			swap(arr, i, minIndex);//将这个下标与对应位置的数交换位置
		}
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

对于其时间复杂度来说 在每找到一个小值时均会进行N-k比较(k表示为已经找到几个小值),这些比较操作均为常数操作则有(n-1)+(n-2)+(n-3)+…1次比较常数操作,n次交换操作,n次赋值操作,由等差数列求和公式可得an^2 +bn+c 次常数操作,则由上文的时间复杂度公式可得:其时间复杂度为 O(n^2)。
注意当两个算法的时间复杂度相同但想要得到这两个算法在运行时间上的优劣时最好采用直接用大数据量跑一遍的方法进行比较而不是用他们进行了多少次常数操作进行比较,因为不同的常数操作虽然每一次所需的时间是相同的但是不同的常数操作之间所需的时间是不同的故最好还是用大数据量跑一遍

冒泡排序

冒泡排序通过重复遍历要排序的数列,比较每对相邻元素的大小,并在必要时交换它们的位置。这个过程会重复进行,直到没有再需要交换的元素为止,这意味着数列已经排序完成。

public static void bubbleSort(int[] arr) {
        //数组过滤(如果数组不存在或数组数组只有一个元素便不需要排序)
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int e = arr.length - 1; e > 0; e--) {
			for (int i = 0; i < e; i++) {//遍历数组如果当前数大于其后一个数则这两数交换位置即冒泡
				if (arr[i] > arr[i + 1]) { 
					swap(arr, i, i + 1);
				}
			}
		}
	}

	public static void swap(int[] arr, int i, int j) {
		arr[i] = arr[i] ^ arr[j];
		arr[j] = arr[i] ^ arr[j];
		arr[i] = arr[i] ^ arr[j];
	}

插入排序

插入排序通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因此它对于小数据量的排序效率很高。
将第一个元素视为已排序序列,从第二个元素开始进行排序。先取出一个待排序的元素,将其与已排序序列中的元素从后向前比较。如果待插入的元素比已排序序列中的某个元素小,则将那个元素向后移动一个位置。
重复这个过程,直到找到一个合适的位置,或者到达已排序序列的开始。后将待排序元素插入到找到的合适位置。
对每一个待排序元素重复步骤,直到所有元素都被插入到已排序序列中。

public static void insertionSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		for (int i = 1; i < arr.length; i++) {
			for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
				swap(arr, j, j + 1);
			}
		}
	}

	public static void swap(int[] arr, int i, int j) {
		arr[i] = arr[i] ^ arr[j];
		arr[j] = arr[i] ^ arr[j];
		arr[i] = arr[i] ^ arr[j];
	}

归并排序

归并排序采用分治法(Divide and Conquer)的思想。归并排序将数组分成两半,分别对这两半进行排序,然后将排序好的两部分合并在一起。以下是归并排序的基本思想和步骤:
将数组分成两半,直到每个子数组只有一个元素。一个元素的数组是有序的。
递归地对每个子数组进行归并排序。
将两个有序的子数组合并成一个有序的数组。

合并两个有序数组的基本思想如下:
比较两个子数组的首元素,选择较小的元素放入合并后的数组。
移动选择的元素到下一个位置,继续比较两个子数组的首元素。
重复上述过程,直到一个子数组的所有元素都被合并。
将另一个子数组的剩余元素直接复制到合并后的数组

public static void mergeSort(int[] arr, int[] arrSorted, int left, int right) {
        if (left < right) {
            // 找到中间索引
            int middle = (left + right) / 2;

            // 分别对左右两部分进行归并排序
            mergeSort(arr, arrSorted, left, middle);
            mergeSort(arr, arrSorted, middle + 1, right);

            // 合并两个有序数组
            merge(arr, arrSorted, left, middle, right);
        }
    }

    // 合并两个有序数组的函数
    public static void merge(int[] arr, int[] arrSorted, int left, int middle, int right) {
        int i, j, k;
        i = left;    // 左数组的起始索引
        j = middle + 1;  // 右数组的起始索引
        k = left;    // 合并后数组的起始索引

        // 合并过程
        while (i <= middle && j <= right) {
            if (arr[i] < arr[j]) {
                arrSorted[k++] = arr[i++];
            } else {
                arrSorted[k++] = arr[j++];
            }
        }

        // 复制剩余的元素
        while (i <= middle) {
            arrSorted[k++] = arr[i++];
        }

        while (j <= right) {
            arrSorted[k++] = arr[j++];
        }

        // 将合并后的数组复制回原数组
        for (i = left; i <= right; i++) {
            arr[i] = arrSorted[i];
        }
    }
小和问题
问题描述

小和问题
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组
的小和。求一个数组 的小和。
例子:[1,3,4,2,5] 1左边比1小的数,没有; 3左边比3小的数,1; 4左
边比4小的数,1、3; 2左边比2小的数,1; 5左边比5小的数,1、3、4、
2; 所以小和为1+1+3+1+1+3+4+2=16

解题思路

小和问题可以看成求一个数右边有多少个数比他大如果比他大便将其自身加入到求小和的过程中,因此这个问题可以用归并排序的算法进行求解,在归并排序的merge阶段对左边界的数进行遍历得到每个数与右边界的数的大小关系,得到右边界的数中有多少数大于左边界对应的数,并将这些数乘积后加入到最后的结果中,并在最后得到结果。

public static int smallSum(int[] arr) {
		if (arr == null || arr.length < 2) {
			return 0;
		}
		return mergeSort(arr, 0, arr.length - 1);
	}

	public static int mergeSort(int[] arr, int l, int r) {
		if (l == r) {
			return 0;
		}
		int mid = l + ((r - l) >> 1);
		return mergeSort(arr, l, mid) 
				+ mergeSort(arr, mid + 1, r) 
				+ merge(arr, l, mid, r);
	}

	public static int merge(int[] arr, int l, int m, int r) {
		int[] help = new int[r - l + 1];
		int i = 0;
		int p1 = l;
		int p2 = m + 1;
		int res = 0;
		while (p1 <= m && p2 <= r) {
			res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;
			help[i++] = arr[p1] < arr[p2] ?000000000000 arr[p1++] : arr[p2++];
		}
		while (p1 <= m) {
			help[i++] = arr[p1++];
		}
		while (p2 <= r) {
			help[i++] = arr[p2++];
		}
		for (i = 0; i < help.length; i++) {
			arr[l + i] = help[i];
		}
		return res;
	}

快速排序

荷兰国旗问题
问题描述

将一个数根据一个特定的数划分为小于该数、等于该数、大于该数这三部分

public static int[] partition(int[] arr, int l, int r) {
		int less = l - 1;
		int more = r;
		while (l < more) {
			if (arr[l] <; arr[r]) {
				swap(arr, ++less, l++);
			} else if (arr[l] > arr[r]) {
				swap(arr, --more, l);
			} else {
				l++;
			}
		}
		swap(arr, more, r);
		return new int[] { less + 1, more };
	}

快速排序便是将这个进行递归 便能排好序

public static void quickSort(int[] arr) {
		if (arr == null || arr.length &lt; 2) {
			return;
		}
		quickSort(arr, 0, arr.length - 1);
	}

	public static void quickSort(int[] arr, int l, int r) {
		if (l &lt; r) {
			swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
			int[] p = partition(arr, l, r);
			quickSort(arr, l, p[0] - 1);
			quickSort(arr, p[1] + 1, r);
		}
	}

	public static int[] partition(int[] arr, int l, int r) {
		int less = l - 1;
		int more = r;
		while (l &lt; more) {
			if (arr[l] &lt; arr[r]) {
				swap(arr, ++less, l++);
			} else if (arr[l] &gt; arr[r]) {
				swap(arr, --more, l);
			} else {
				l++;
			}
		}
		swap(arr, more, r);
		return new int[] { less + 1, more };
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

堆排序

堆排序算法基于大根堆(最大堆)或小根堆(最小堆)的数据结构。堆排序的基本思想是将无序序列构建成一个堆,然后逐个从堆中取出元素,将其放在序列的末尾,同时重新调整堆,直到堆中只剩下一个元素,此时整个序列就成为了有序序列。
构建最大堆:将无序序列构建成一个最大堆(大根堆)。
交换并重建堆:将堆顶元素(最大值)与序列末尾元素进行交换,然后将序列末尾的元素移除(即缩小堆的大小),并重新调整堆以保持最大堆的性质。
重复交换:重复步骤2,直到堆中只剩下一个元素。

堆结构
大根堆

对于任意一个非叶子节点i(其子节点为2i+1和2i+2,其中索引从0开始),其值总是大于或等于其子节点的值,即:

A[i] >= A[2i+1]
A[i] >= A[2
i+2]
其中A是存储堆的数组,且A[0]是根节点。

小根堆

对于任意一个非叶子节点i(其子节点为2i+1和2i+2,其中索引从0开始),其值总是小于或等于其子节点的值,即:

A[i] <= A[2i+1]
A[i] <= A[2
i+2]
其中A是存储堆的数组,且A[0]是根节点。

public class HeapSort {
    // 堆调整函数,用于调整节点i,确保子树满足最大堆的性质
    private static void heapify(int[] arr, int n, int i) {
        int largest = i; // 初始化最大值为根节点
        int left = 2 * i + 1; // 左子节点
        int right = 2 * i + 2; // 右子节点

        // 如果左子节点大于根节点,则更新最大值
        if (left < n && arr[left] > arr[largest]) {
            largest = left;
        }

        // 如果右子节点大于当前最大值,则更新最大值
        if (right < n && arr[right] > arr[largest]) {
            largest = right;
        }

        // 如果最大值不是根节点,交换它们,并继续调整堆
        if (largest != i) {
            int swap = arr[i];
            arr[i] = arr[largest];
            arr[largest] = swap;

            // 递归调整被交换节点的子树
            heapify(arr, n, largest);
        }
    }

    // 堆排序函数
    public static void heapSort(int[] arr) {
        int n = arr.length;

        // 构建最大堆
        for (int i = n / 2 - 1; i >= 0; i--) {
            heapify(arr, n, i);
        }

        // 一个个从堆中取出元素并放到数组末尾
        for (int i = n - 1; i >= 0; i--) {
            // 交换堆顶元素和数组末尾元素
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;

            // 调整堆
            heapify(arr, i, 0);
        }
    }
}

桶排序

桶排序(Bucket Sort)是一种分布式排序算法,它将数组分为多个桶,每个桶负责排序数组中的一部分数据。桶排序的基本思想是将数据分散到有限数量的桶里,每个桶再分别对各自范围内的数据进行排序,最后依次取出每个桶排序后的数据,从而得到有序的序列。
先根据数据的范围和数据的分布,确定桶的数量。再遍历待排序的数组,将每个元素放入其对应的桶中。通常使用一个函数映射数据到桶的索引。之后对每个桶内的数据使用其他排序算法(如插入排序、快速排序等)进行排序。
最后依次从各个桶中取出数据,并将它们拼接起来,形成有序序列。

public static void radixSort(int[] arr) {
		if (arr == null || arr.length &lt; 2) {
			return;
		}
		radixSort(arr, 0, arr.length - 1, maxbits(arr));
	}

	public static int maxbits(int[] arr) {
		int max = Integer.MIN_VALUE;
		for (int i = 0; i &lt; arr.length; i++) {
			max = Math.max(max, arr[i]);
		}
		int res = 0;
		while (max != 0) {
			res++;
			max /= 10;
		}
		return res;
	}

	public static void radixSort(int[] arr, int begin, int end, int digit) {
		final int radix = 10;
		int i = 0, j = 0;

		int[] bucket = new int[end - begin + 1];
		for (int d = 1; d &lt;= digit; d++) {
			int[] count = new int[radix];
			for (i = begin; i &lt;= end; i++) {
				j = getDigit(arr[i], d);
				count[j]++;
			}
			for (i = 1; i &lt; radix; i++) {
				count[i] = count[i] + count[i - 1];
			}
			for (i = end; i &gt;= begin; i--) {
				j = getDigit(arr[i], d);
				bucket[count[j] - 1] = arr[i];
				count[j]--;
			}
			for (i = begin, j = 0; i &lt;= end; i++, j++) {
				arr[i] = bucket[j];
			}
		}
	}

	public static int getDigit(int x, int d) {
		return ((x / ((int) Math.pow(10, d - 1))) % 10);
	}

二分

二分搜索

二分搜索它通过反复将搜索区间一分为二来缩小搜索范围,直到找到目标值或搜索区间为空。
首先,确定要搜索的有序数组的起始索引(通常为0)和结束索引(通常是数组长度减1)。
计算当前搜索区间的中间索引mid,公式为mid = (low + high) / 2。
将中间索引处的元素与目标值进行比较。
如果中间元素等于目标值,则搜索成功,返回中间索引。
如果中间元素大于目标值,则在数组的左半部分继续搜索。
如果中间元素小于目标值,则在数组的右半部分继续搜索。
根据比较结果,更新搜索区间的起始索引或结束索引。
如果中间元素大于目标值,更新high为mid - 1。
如果中间元素小于目标值,更新low为mid + 1。
重复步骤,直到找到目标值或搜索区间为空(即low大于high)。
如果搜索区间为空,说明数组中不存在目标值,返回一个表示失败的标志(通常是-1或其他特定的值)。

public static int binarySearch(int[] arr, int target) {
        int low = 0;
        int high = arr.length - 1;

        while (low <= high) {
            // 计算中间索引,防止溢出
            int mid = low + (high - low) / 2;

            // 检查中间元素是否是目标值
            if (arr[mid] == target) {
                return mid; // 找到目标值,返回索引
            }

            // 如果中间元素大于目标值,调整搜索区间的高索引
            if (arr[mid] > target) {
                high = mid - 1;
            } else {
                // 如果中间元素小于目标值,调整搜索区间的低索引
                low = mid + 1;
            }
        }

        // 未找到目标值,返回-1
        return -1;
    }

^的运用

不用额外空间交换两个数的值

在这里插入图片描述

int a=a^b;
int b=a^b;
int a=a^b;

数组中存在一个数有奇数次,其他数均出现偶数次,找到那个出现奇数次的数

以此数组为例
在这里插入图片描述
该数组中1出现4次 ,2出现两次,3出现三次
则可用下列这种方法解决。其原理为同一个数异或偶数次后得到的结果一定为0,0异或一个数结果一定为该数,
在这里插入图片描述
由于异或操作的结果与顺序无关则上述代码可改成
在这里插入图片描述
则两个1异或后为0… 两个2异或后为0 , 两个3异或后为0,最后结果为0异或3为3,即为数组中出现奇数次的元素。

对数器

对数器的概念和使用

1,有一个你想要测的方法a
2,实现复杂度不好但是容易实现的方法b
3,实现一个随机样本产生器
4,把方法a和方法b跑相同的随机样本,看看得到的结果是否一样。
5,如果有一个随机样本使得比对结果不一致,打印样本进行人工干预,改对方法a或者
方法b
6,当样本数量很多时比对测试依然正确,可以确定方法a已经正确。

// for test
	public static void comparator(int[] arr) {
		Arrays.sort(arr);
	}

	// for test
	public static int[] generateRandomArray(int maxSize, int maxValue) {
		int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
		for (int i = 0; i &lt; arr.length; i++) {
			arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
		}
		return arr;
	}

	// for test
	public static int[] copyArray(int[] arr) {
		if (arr == null) {
			return null;
		}
		int[] res = new int[arr.length];
		for (int i = 0; i &lt; arr.length; i++) {
			res[i] = arr[i];
		}
		return res;
	}

	// for test
	public static boolean isEqual(int[] arr1, int[] arr2) {
		if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
			return false;
		}
		if (arr1 == null && arr2 == null) {
			return true;
		}
		if (arr1.length != arr2.length) {
			return false;
		}
		for (int i = 0; i &lt; arr1.length; i++) {
			if (arr1[i] != arr2[i]) {
				return false;
			}
		}
		return true;
	}

	// for test
	public static void printArray(int[] arr) {
		if (arr == null) {
			return;
		}
		for (int i = 0; i &lt; arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}

	// for test
	public static void main(String[] args) {
		int testTime = 500000;
		int maxSize = 100;
		int maxValue = 100;
		boolean succeed = true;
		for (int i = 0; i &lt; testTime; i++) {
			int[] arr1 = generateRandomArray(maxSize, maxValue);
			int[] arr2 = copyArray(arr1);
			selectionSort(arr1);
			comparator(arr2);
			if (!isEqual(arr1, arr2)) {
				succeed = false;
				printArray(arr1);
				printArray(arr2);
				break;
			}
		}
		System.out.println(succeed ? "Nice!" : "Fucking fucked!");

		int[] arr = generateRandomArray(maxSize, maxValue);
		printArray(arr);
		selectionSort(arr);
		printArray(arr);
	}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++读写.xlsx文件】OpenXLSX开源库在 Ubuntu 18.04 的编译、交叉编译与使用教程

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-12-17 …

汽车电子零部件(15):AVM全景影像系统

概述: 使用ADAS全景监控(AVM)精确停车和操纵。这项先进技术采用多个摄像头,提供车辆周围环境的鸟瞰图。 360度全景监控系统: 360 AVM系统可以帮助驾驶员360度查看车辆周围的情况,避免发生碰撞。360 AVM系统由一个电子控制单元(ECU)和四个摄像头组成。ECU将处理四个摄…

C语言习题2.0

C语言习题1.0 C语言习题-CSDN博客 目录 C语言习题1.0 C语言习题-CSDN博客 找一个数字的连续因子 求N个分数的和 正整数AB 函数 预处理 文件处理 操作符 找一个数字的连续因子 //找连续因子,及其个数 int main() {int a;scanf("%d", &a);int num 0; …

flask flask-socketio创建一个网页聊天应用

应用所需环境&#xff1a; python 3.11.11 其他 只需要通过这个命令即可 pip install flask3.1.0 Flask-SocketIO5.4.1 -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple 最好是用conda创建一个新的虚拟环境来验证 完整的pip list如下 Package Version ----…

重拾设计模式--观察者模式

文章目录 观察者模式&#xff08;Observer Pattern&#xff09;概述观察者模式UML图作用&#xff1a;实现对象间的解耦支持一对多的依赖关系易于维护和扩展 观察者模式的结构抽象主题&#xff08;Subject&#xff09;&#xff1a;具体主题&#xff08;Concrete Subject&#xf…

正则表达式优化之算法和效率优化

正则表达式优化之算法和效率优化 前言 正则表达式是处理文本匹配的强大工具&#xff0c;但在实际应用中&#xff0c;如果不加以优化&#xff0c;可能会导致性能问题或匹配结果不精确。 本文将分三篇从表达式结构、算法效率和实际应用场景三个方面. 深入探讨如何优化正则表达…

workman服务端开发模式-应用开发-gateway长链接端工作原理

一、长链接的工作原理 Register类其实也是基于基础的Worker开发的。Gateway进程和BusinessWorker进程启动后分别向Register进程注册自己的通讯地址&#xff0c;Gateway进程和BusinessWorker通过Register进程得到通讯地址后&#xff0c;就可以建立起连接并通讯了。而Gateway进程…

排序算法 (插入,选择,冒泡,希尔,快速,归并,堆排序)

排序:经常在算法题中作为一个前置操作,为了之后的贪心or else做个铺垫,虽然我们经常都只是调用个sort,但是了解一些排序算法可以扩充下知识库 排序的分类: 从存储设备角度&#xff1a; ✓ 内排序&#xff1a;在排序过程中所有数据元素都在内存中&#xff1b; ✓ 外排序&a…

云途领航:现代应用架构助力企业转型新篇

在数字化转型的浪潮中&#xff0c;现代应用架构为企业带来了灵活性、效率和创新能力。各类服务模型相继出现&#xff0c;为企业提供了强有力的支持&#xff0c;助力其顺利转型。随着技术的快速发展&#xff0c;企业面临的挑战和机遇也在不断演变&#xff0c;这促使它们必须重新…

【IMU:视觉惯性SLAM系统】

视觉惯性SLAM系统简介 相机&#xff08;单目/双目/RGBD)与IMU结合起来就是视觉惯性&#xff0c;通常以单目/双目IMU为主。 IMU里面有个小芯片可以测量角速度与加速度&#xff0c;可分为6轴(6个自由度)和9轴&#xff08;9个自由度&#xff09;IMU&#xff0c;具体的关于IMU的介…

面试题整理3----nc命令的常见用法

面试题整理3----nc命令的常见用法 1. NC是什么2. NC的常用参数2.1 开启指定端口TCP监听(-l小写的L)2.2 测试端口是否能访问(-v)2.3 开启指定端口UDP监听(-u)2.4 端口扫描(-z)2.5 指定超时时间(-w)2.6 指定本地端口号连接(-p)2.7 指定的命令(-e) 1. NC是什么 nc&#xff08;Net…

ubuntu 如何重装你的apt【apt-get报错: symbol lookup error/undefined symbol】

副标题:解决error:apt-get: symbol lookup error: /lib/x86_64-linux-gnu/libapt-private.so.0.0: undefined symbol: _ZNK13pkgTagSection7FindULLENS_3KeyERKy, version APTPKG_6.0 文章目录 问题描述报错分析解决方案:重装你的apt1、查看你的ubuntu版本2、下载适配你的ap…

解决:excel鼠标滚动幅度太大如何调节?

在excel里为什么滚动一次跳过很多行呢&#xff1f;很不方便。。。 1. 问题&#xff1a; 一开始单元格从第1行开始&#xff1a; 鼠标轻轻滚动一下后&#xff0c;直接跳到第4行&#xff1a; 鼠标在word和浏览器里都是好好的。在excel里为什么不是滚动一次跳过一行呢&#xff…

VMWare 的克隆操作

零、碎碎念 VMWare 的这个克隆操作很简单&#xff0c;单拎出来成贴的目的是方便后续使用。 一、操作步骤 1.1、在“源”服务器上点右键&#xff0c;选择“管理--克隆” 1.2、选择“虚拟机的当前状态”为基础制作克隆&#xff0c;如下图所示&#xff0c;然后点击“下一页” 1.3、…

ARM 处理器平台 Ethernet Compliance 测试流程示例

By Toradex秦海 1). 简介 为了保证基于IEEE 802.3 协议设计的以太网设备接口可以互相兼容互联互通&#xff0c;需要进行 Ethernet Compliance 一致性测试&#xff0c;相关的技术原理说明请参考如下文章&#xff0c;本文就不赘述&#xff0c;主要展示基于 NXP i.MX8M Mini ARM…

门控循环单元(GRU):深度学习中的序列数据处理利器

目录 ​编辑 引言 GRU的诞生背景 GRU的核心机制 GRU的计算过程 GRU的数学公式 GRU的应用领域 代码示例&#xff1a;PyTorch中的GRU GRU与LSTM的比较 参数比较 GRU的技术发展 BiGRU&#xff08;双向GRU&#xff09; BiGRU的实现示例 GRU与CNN的结合 GRU的应用案例…

C#都可以找哪些工作?

在国内学习C#&#xff0c;可以找的工作主要是以下4个&#xff1a; 1、游戏开发 需要学习C#编程、Unity引擎操作、游戏设计和3D图形处理等。 2、PC桌面应用开发 需要学习C#编程、WinForm框架/WPF框架、MVVM设计模式和UI/UX设计等。 3、Web开发 需要学习C#编程、ASP.NET框架…

视频直播点播平台EasyDSS与无人机技术的森林防火融合应用

随着科技的飞速发展&#xff0c;无人机技术以其独特的优势在各个领域得到了广泛应用&#xff0c;特别是在森林防火这一关键领域&#xff0c;EasyDSS视频平台与无人机技术的融合应用更是为传统森林防火手段带来很大的变化。 一、无人机技术在森林防火中的优势 ‌1、快速响应与高…

【编译原理】编译原理知识点汇总·词法分析器(正则式到NFA、NFA到DFA、DFA最小化)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;编译原理_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …

SAP抓取外部https报错SSL handshake处理方法

一、问题描述 SAP执行报表抓取https第三方数据,数据获取失败。 报错消息: SSL handshake with XXX.COM:449 failed: SSSLERR_SSL_READ (-58)#SAPCRYPTO:SSL_read() failed##SapSSLSessionStartNB()==SSSLERR_SSL_READ# SSL:SSL_read() failed (536875120/0x20001070)# …