七大经典比较排序算法

1. 插入排序 (⭐️⭐️)

🌟 思想:

直接插入排序是一种简单的插入排序法,思想是是把待排序的数据按照下标从小到大,依次插入到一个已经排好的序列中,直至全部插入,得到一个新的有序序列例如:我们玩扑克牌的时候,每次摸进一张的新的牌我们会将其插入到合适的位置。

思路: 我们假设第一个数据有序,从第二个元素开始进行插入(最开始把前面第一个数据看作一个有序的区间),从后向前依次寻找合适位置,每次插入的时候如果当前位置不合适将当前位置向后移动一位。

InsertSort 实现:

// 插入排序
void InsertSort(int * nums , int size) {for (int i = 0; i < size - 1; i++) {// 把 [0 , end] 看作有序区间int end = i;// nums[end + 1]为需要插入的元素 使用 temp 保存int temp = nums[end + 1];// 找插入位置while (end >= 0 && temp < nums[end]) {// 把当前元素向后移动nums[end + 1] = nums[end];end--;}// 来到这里说明 temp >= nums[end] 找到插入位置// 插入nums[end + 1] = temp;}
}

我们可以思考一下极端情况:

  • 假设数据为 3 5 7end1temp = 7,所以 temp < nums[end] false 循环结束,执行 nums[end + 1] = temp,相当于 nums[2] = 7 而当前位置本来就是 7,不会有影响。
  • 假设数据为 3 5 1end1temp = 1,当前 temp < nums[end] 将数据向后移动直至 3 3 5,当 end = -1循环结束,nums[end + 1] = temp 相当于 nums[0] = temp,所以最终结果为 1 3 5

总结:

  1. 元素结合越接近有序,直接插入排序算法的时间效率就越高。
  2. 最坏时间复杂度: O ( N 2 ) O(N^2) O(N2)
  3. 接近有序或已经有序时间复杂度: O ( N ) O(N) O(N)
  4. 空间复杂度: O ( 1 ) O(1) O(1)

2.希尔排序 (⭐️⭐️⭐️)

🌟 思想:

希尔排序又称缩小增量法。希尔排序的基本思想是:先选定一个 gap (整数),把待排序中的数据分成 gap 组(gap 距离的为同一组),并对每一组内的的数据进行插入排序。

假设 gap = 3 将下面的 10 个数分成 3 组。 {9 , 5 , 8 , 5}{1 , 7 , 6}{2 , 4 , 3}分别进行插入排序。当 gap 不为 1 时都是预排序,当 gap = 1时是插入排序,因为当数据接近有序的时候,插入排序的效率很高。

在这里插入图片描述


1️⃣ gap 组希尔排序: 这是希尔排序的 gap 组的一种写法,按上面的图来说,这样的写法是先走完红色组,再走蓝色组……

void ShellSort (int * nums , int size) {assert(nums);// 假设 gap = 3int gap = 3;for (int j = 0; j < gap; j++) {for (int i = j; i < size - gap; i+=gap) {int end = i;int temp = nums[end + gap];while (end >= 0 && temp < nums[end]) {nums[end + gap] = nums[end];end -= gap;}nums[end + gap] = temp;}}
}

2️⃣ gap 组希尔排序:第二种在上一种写法上进行了优化,原来是一组走完再走下一组,现在是一组一组间交替的去插入排序。

void ShellSort (int * nums , int size) {assert(nums);// 假设 gap = 3int gap = 3;for (int i = 0; i < size - gap; i++) {int end = i;int temp = nums[end + gap];while (end >= 0 && temp < nums[end]) {nums[end + gap] = nums[end];end -= gap;}nums[end + gap] = temp;}
}

ShellSort 实现:gap > 1 的时候都是预排序(是为了让数据更接近有序,因为直接插入排序当数据接近有序的时候是 O ( N ) O(N) O(N)),而这里 gap / 3 + 1 是为了最后一次让 gap = 1gap 越大的时候大的数会越快的到后面,但是数组越不接近有序。当 gap 越小的时候,数组越接近有序。当 gap = 1 就是直接插入排序。

void ShellSort (int * nums , int size) {assert(nums);int gap = size;while (gap > 1) {gap = gap / 3 + 1;for (int i = 0; i < size - gap; i++) {int end = i;int temp = nums[end + gap];while (end >= 0 && temp < nums[end]) {nums[end + gap] = nums[end];end -= gap;}nums[end + gap] = temp;}}
}

总结:

  1. 时间复杂度 ~ O ( N 1.3 ) O(N^{1.3}) O(N1.3)
  2. 空间复杂度: O ( 1 ) O(1) O(1)
  3. 希尔排序是插入排序的优化

3. 选择排序 (⭐️)

🌟 思想:

每一次从待排序的数据种选出最小或者最大的元素下标,存放在当前序列的起始位置,直到排序结束。

请添加图片描述

1️⃣SelectSort 实现:

// 选择排序
void SelectSort(int * nums , int size) {assert(nums);for (int i = 0; i < size - 1; i++) {int minIndex = i + 1;// 选数for (int j = i + 1; j < size; j++) {if (nums[j] < nums[minIndex ]) {minIndex = j;}}// 交换int temp = nums[minIndex];nums[minIndex] = nums[i];nums[i] = temp;}
}

2️⃣ SelectSort 优化: 我们可以同时选出两个数一个最大一个最小,把最小的组交换到当前区间的左边,最大的交换到区间的右边。

void SelectSort(int * nums , int size) {assert(nums);int left = 0;int right = size - 1;while (left < right) {// 最小值下标默认从左区间开始int maxIndex = left;int minIndex = left;for (int i = left + 1; i <= right; i++) {if (nums[i] > nums[maxIndex]) {maxIndex = i;}if (nums[i] < nums[minIndex]) {minIndex = i;}}// 交换Swap(&nums[left] , &nums[minIndex]);// 特殊情况:假设第一个位置就是最大值 那么做完第一次交换最小的值到最左边// 而最大值被交换到了原来最小值的位置if (left == maxIndex) {maxIndex = minIndex;}Swap(&nums[right] , &nums[maxIndex]);left++;right--;}
}

Swap 实现:

// 交换
void Swap(int* val1, int* val2) {int temp = *val1;*val1 = *val2;*val2 = temp;
}

总结:

  1. 选择排序比较好理解,但是效率很低,实际种很少使用。
  2. 时间复杂度 O ( N 2 ) O(N^2) O(N2)

4. 堆排序 (⭐️⭐️⭐️)

🌟 思想:

堆排序是指用堆这种数据结构所设计的一种排序思想,它是选择排序的一种,它是用堆来进行选数。升序需要建大堆,降序需要建小堆。

拿升序来举例,因为大堆的堆顶是最大的数,此时我们可以让堆顶和末尾元素交换。再让堆顶的元素向下调整(只不过此时向下调整,我们先让数组的长度减 1,因为最大的数已经到末尾的位置了,不必算入堆内)

AdjustDown 实现(大堆举例):

// 堆的向下调整算法
void AdjustDown(int * nums , int size , int parent) {assert(nums);// 默认左孩子最大int child = 2 * parent + 1;while (child < size) {// 选出左右孩子最大的孩子if (child + 1 < size && nums[child + 1] > nums[child]) {child++;}// 最大的孩子比父亲还大则调整if (nums[child] > nums[parent]) {Swap(&nums[child] , &nums[parent]);// 继续向下搜索parent = child;child = parent * 2 + 1;} else {break;}}
}

AdjustUp 实现(大堆举例):

// 堆的向上调整算法
void AdjustUp (int * nums , int child) {int parent = (child - 1) / 2;// 当孩子 = 0的时候已经没有父亲节点了while (child > 0) {if (nums[child] > nums[parent]) {Swap(&nums[child] , &nums[parent]);// 继续向上搜索child = parent;parent = (child - 1) / 2;} else {break;}}
}

HeapSort 实现:

// 堆排序
void HeapSort(int * nums , int size) {assert(nums);// 先建堆// 向上调整算法建堆// for (int i = 1; i < size; i++) {// AdjustUp(nums , i);// }// 向下调整算法建堆// 向下调整的前提是:左右子树必须都是堆// 所以大堆从第一个非叶子节点开始向下调整for (int parent = (size - 1 - 1) / 2; parent >= 0; parent--) {AdjustDown(nums , size , parent);}// 排序int end = size - 1;while (end > 0) {// 堆顶元素和末尾元素交换Swap(&nums[0] , &nums[end]);	AdjustDown(nums , end , 0);end--;}
}

总结:

  1. 堆排序的时间复杂度 O ( N ∗ l o g N ) O(N*logN) O(NlogN)
  2. 向上调整算法建堆的时间复杂度是 O ( N ∗ l o g N ) O(N * logN) O(NlogN),向下调整算法建堆的时间复杂度是 O ( N ) O(N) O(N),但是向下调整算法建堆的前提是:当前左右子树必须是堆。所以向下调整算法要从非叶子节点开始向下调整,最后一个非叶子节点就是最后一个元素的父节点 (size - 1 - 1) / 2

5. 冒泡排序 (⭐️⭐️)

🌟 思想:

冒泡排序是交换排序的一种。所谓交换就是根据序列中两个记录下标值的比较结果来对这一对数据进行交换,当第一躺冒泡排序结束后,若是升序会把最大的数冒到最后末尾,以此类推。

BubbleSort 实现:

// 冒泡排序
void BubbleSort(int* nums, int size) {assert(nums);for (int i = 0; i < size - 1; i++) {for (int j = 0; j < size - 1 - i; j++) {if (nums[j] > nums[j + 1]) {Swap(&nums[j] , &nums[j + 1]);}}}
}

BubbleSort 优化:当数组为有序的时候,我们用 enchage 来记录,若当前这一趟一次都没有交换,则数组已经有序。

// 冒泡排序
void BubbleSort(int* nums, int size) {assert(nums);for (int i = 0; i < size - 1; i++) {int exchage = 1;for (int j = 0; j < size - 1 - i; j++) {if (nums[j] > nums[j + 1]) {exchage = 0;Swap(&nums[j] , &nums[j + 1]);}}if (exchage) {break;}}
}

总结:

  1. 冒泡排序是非常经典的排序
  2. 时间复杂度 O ( N 2 ) O(N^2) O(N2)

6. 快速排序 (⭐️⭐️⭐️⭐️)

🌟 思想:

快速排序是 Hoare于1962年提出的一种二叉树结构的交换排序方法。基本思想是:从待排序序列中选一个 key(通常为最左边或者最右边),按照 key 把待排序序列分成两个子序列,左序列中的元素都 < key,右序列的元素都 > key,然后左右序列重复该过程,直到所有元素都排列在对应的位置上。

在这里插入图片描述


1.hoare版本:

思路和结论:假设 key 为最左边的数,那么就要先从右边走,再走左边。假设 key 为最右边的数,那么就要从左边先走,再走右边。这样做的目的是:当 leftright 相遇结束的时候,让 key 位置的元素与当前相遇位置交换,而当前相遇位置一定能保证比 key 要小(或大)。 第一次快速排序相当于处理好了第一个区间,因为 key 找到了合适的位置左面的数都比 key 小,右面的数都比 key 要大,此时只需要让左右区间重复上面的过程。左右区间划分为了 [begin , keyIndex - 1] keyIndex [keyIndex + 1 , end]。递归处理即可,当左右区间只剩一个数(begin == end)或者区间不存在(begin > end)的时候为递归结束条件。

QucikSort实现:

void QuickSort(int * nums , int begin , int end) {// 只剩一个数或者区间不存在不需要处理if (begin >= end) {return;}int left = begin;int right = end;// key 默认为最左边的数字int keyIndex = left;while (left < right) {// 右边先走,找小while (left < right && nums[right] >= nums[keyIndex]) {right--;}// 左边找大while (left < right && nums[left] <= nums[keyIndex]) {left++;}// 交换Swap(&nums[left] , &nums[right]);}// 相遇位置和 keyIndex 交换Swap(&nums[keyIndex] , &nums[left]);// 更改 keyIndexkeyIndex = left;QuickSort(nums , begin , keyIndex - 1);QuickSort(nums , keyIndex + 1, end);
}

💬 思考问题:

  1. nums[left] <= nums[keyIndex]nums[right] >= nums[keyIndex] 这里为什么要使用 =不使用 = 可以吗?结论是不可以。

    在这里插入图片描述


  1. 为什么右边和左边走的时候要加上 left < right

在这里插入图片描述


  1. 为什么 key 如果是左边的数就要先从右边走呢?左边先走可以吗?结论是不可以。
    在这里插入图片描述

2.挖坑版本:

思路:先将最左面的数据存在一个临时变量 key 中,这样当前 key 这个位置就是一个坑位。右面 right 找小,找到之后把小的数填到当前坑中 nums[keyIndex] = nums[right],此时更换坑的位置 keyIndex = right。左面 left 找大,找到之后把大的数继续填到当前坑中 nums[keyIndex] = nums[left],此时继续更换坑的位置 keyIndex = left。当 leftright 相遇时在把 key 填入相遇(坑位)位置。

QucikSort实现:

void QuickSort(int * nums , int begin , int end) {// 只剩一个数或者区间不存在不需要处理if (begin >= end) {return;}int left = begin;int right = end;// 保存当前坑的元素int key= nums[left];// 坑位int keyIndex = left;while (left < right) {while (left < right && nums[right] >= key) {right--;}// 填坑nums[keyIndex] = nums[right];// 更换坑的位置keyIndex = right;while (left < right && nums[left] <= key) {left++;}// 填坑nums[keyIndex] = nums[left];// 更换坑的位置keyIndex = left;}// 循环结束填入当前坑位nums[keyIndex] =  key;QuickSort(nums , begin , keyIndex - 1);QuickSort(nums , keyIndex + 1, end);
}

注:同样一组数,使用 hoare 思想和挖坑法思想进行一轮快排的结果是不同的。

例如:{6 , 1 , 2 , 7 , 9 , 3 , 4 , 5 , 10 , 8}

  1. hoare: 第一次交换 {6 , 1 , 2 , 5 , 9 , 3 , 4 , 7 , 10 , 8}、第二次交换 {6 , 1 , 2 , 5 , 4 , 3 , 9 , 7 , 10 , 8}、循环结束相遇位置与 keyIndex 位置交换 {3 , 1 , 2 , 5 , 4 , 6 , 9 , 7 , 10 , 8} 最终结果。

  2. 挖坑法: 第一次挖坑 {5 , 1 , 2 , 7 , 9 , 3 , 4 , (5) , 10 , 8}、第二次 {5 , 1 , 2 , (7) , 9 , 3 , 4 , 7 , 10 , 8}、第三次 {5 , 1 , 2 , 4 , 9 , 3 , (4) , 7 , 10 , 8}、第四次 {5 , 1 , 2 , 4 , (9) , 3 , 9 , 7 , 10 , 8}、第五次 {5 , 1 , 2 , 4 , 3 , (3) , 9 , 7 , 10 , 8}、循环结束把当前坑位填入 key 最终结果是 {5 , 1 , 2 , 4 , 3 , 6 , 9 , 7 , 10 , 8}

3.前后指针版本:

思路: 定义一个 prevcurcur 找比 key 要小的数,若找到则 ++prevcur 当前下标的元素进行交换,这样做有一种把小的数翻到前面来,大的往后推。而 prev 后面的数都要比 key 大,最终 cur 越界循环结束,再把 keyIndex 位置和 prev 位置的元素进行交换。

QucikSort 实现:

void QuickSort(int * nums , int begin , int end) {// 只剩一个数或者区间不存在不需要处理if (begin >= end) {return;}int prev = begin;int cur = prev + 1;int keyIndex = begin;while (cur <= end) {if (nums[cur] < nums[keyIndex] && ++prev != cur) {Swap(&nums[prev] , &nums[cur]);}cur++;}Swap(&nums[prev] , &nums[keyIndex]);keyIndex = prev;QuickSort(nums , begin , keyIndex - 1);QuickSort(nums , keyIndex + 1, end);
}

🌟 快排优化

💬 为什么要优化?

因为 key 会影响快排的效率,如果每次的 key 都是中间那个值那么每次都是二分,若每次的 key 都是最小的,最坏情况下快排的时间复杂度 O ( N 2 ) O(N^2) O(N2)。最大的问题是会引起 栈溢出。

1.三数取中优化:

思路: 第一个数和中间还有最后的数,选不是最大也不是最小的数。三数取中主要体现在数据已经有序的情况下。

getMidIndex 实现:

int getMidIndex(int* nums, int begin, int end) {int midIndex = (begin + end) / 2;if (nums[begin] > nums[midIndex]) {// nums[begin] > nums[minIndex]if (nums[midIndex] > nums[end]) {// nums[begin] > nums[minIndex] > nums[end]return midIndex;}else if (nums[begin] > nums[end]) {// nums[begin] > nums[minIndex]// nums[end] >= nums[minIndex]// nums[begin] > nums[end]return end;}else {// nums[begin] > nums[minIndex]// nums[end] >= nums[minIndex]// nums[begin] <= nums[end]return begin;}}else {// nums[begin] <= nums[minIndex]if (nums[begin] > nums[end]) {// nums[begin] <= nums[minIndex]// nums[begin] > nums[end]return begin;}else if (nums[midIndex] > nums[end]) {// nums[begin] <= nums[minIndex]// nums[begin] <= nums[end]// nums[minIndex] > nums[end]return end;}else {// nums[begin] <= nums[minIndex]// nums[begin] <= nums[end]// nums[minIndex] <= nums[end]return midIndex;}}
}

2.小区间优化:

思路: 若只剩最后 10 - 20 个数,还使用快速排序的递归就有点不太划算了。所以当区间较小的时候,就不再使用递归继续划分小区间。考虑直接用其他排序对小区间处理,而希尔排序和堆排序对于数据量小的时候也不太优,所以在简单排序中,插入排序适应性最强。 小区间优化体现在减少递归的调用次数

QuickSort 优化实现:

void QuickSort(int* nums, int begin, int end) {// 只剩一个数或者区间不存在不需要处理if (begin >= end) {return;}if (end - begin > 15) {int prev = begin;int cur = prev + 1;int keyIndex = begin;// 三数取中优化int midIndex = getMidIndex(nums, begin, end);Swap(&nums[keyIndex], &nums[midIndex]);while (cur <= end) {if (nums[cur] < nums[keyIndex] && ++prev != cur) {Swap(&nums[prev], &nums[cur]);}cur++;}Swap(&nums[prev], &nums[keyIndex]);keyIndex = prev;QuickSort(nums, begin, keyIndex - 1);QuickSort(nums, keyIndex + 1, end);} else {// 小区间优化// 插入排序InsertSort(nums + begin  , end - begin + 1);}
}

🌟 快排非递归

QuickSortNoneR 非递归实现:

// 快排非递归(使用栈)
void QucikSortNoneR(int* nums, int begin, int end) {assert(nums);Stack stack;StackInit(&stack);// 区间进栈StackPush(&stack , end);StackPush(&stack, begin);while (!StackEmpty(&stack)) {// 取出左右区间int left = StackTop(&stack);StackPop(&stack);int right = StackTop(&stack);StackPop(&stack);// 快排int keyIndex = left;int prev = left;int cur = prev + 1;while (cur <= right) {if (nums[cur] < nums[keyIndex] && ++prev != cur) {Swap(&nums[prev], &nums[cur]);}cur++;}Swap(&nums[prev], &nums[keyIndex]);keyIndex = prev;// [left , keyIndex - 1] keyIndex [keyIndex + 1 , right]if (keyIndex + 1 < right) {// 区间存在 入栈StackPush(&stack, right);StackPush(&stack, keyIndex + 1);}if (left < keyIndex - 1) {// 区间存在 入栈StackPush(&stack, keyIndex - 1);StackPush(&stack, left);}}StackDestroy(&stack);
}

总结:

  1. 时间复杂度 O ( N ∗ l o g N ) O(N*logN) O(NlogN)
  2. 空间复杂度 O ( l o g N ) O(logN) O(logN)

7. 归并排序 (⭐️⭐️⭐️)

🌟 思想:

归并排序是建立在归并操作上的一种有效的排序算法,是分治的一个典型的应用。将两个有序的子序列归并得到完全有序的序列。归并排序要借助额外的空间。

MergeSort 递归实现:

void merge(int* nums, int begin, int end, int* temp) {// 区间只有一个数或者不存在if (begin >= end) {return;}int midIndex = (begin + end) / 2;// [begin , midIndex] [minIndex + 1 , end]merge(nums , begin , midIndex , temp);merge(nums , midIndex + 1 , end , temp);// 归并int leftBegin = begin;int leftEnd = midIndex;int rightBegin = midIndex + 1;int rightEnd = end;int i = leftBegin;while (leftBegin <= leftEnd && rightBegin <= rightEnd) {if (nums[leftBegin] < nums[rightBegin]) {temp[i++] = nums[leftBegin++];}else {temp[i++] = nums[rightBegin++];}}// 左区间还存在while (leftBegin <= leftEnd) {temp[i++] = nums[leftBegin++];}// 右区间还存在while (rightBegin <= rightEnd) {temp[i++] = nums[rightBegin++];}// 拷贝回原数组memcpy(nums + begin , temp + begin, (end - begin + 1) * sizeof(int));
}// 归并排序
void MergeSort(int* nums, int size) {assert(nums);int* temp = (int*)malloc(sizeof(int) * size);assert(temp);merge(nums , 0 , size - 1 , temp);free(temp);
}

🌟 归并非递归

MergeSort 非递归实现:

// 归并排序非递归
void MergeSortNoneR(int* nums, int size) {assert(nums);int* temp = (int*)malloc(sizeof(int) * size);assert(temp);int gap = 1;while (gap < size) {for (int i = 0; i < size; i += 2 * gap) {int leftBegin = i;int leftEnd = i + gap - 1;int rightBegin = i + gap;int rightEnd = i + 2 * gap - 1;// 检查边界if (leftEnd >= size) {// 修正左区间leftEnd = size - 1;// 让右区间不存在rightBegin = size + 1;rightEnd = size;}else if (rightBegin >= size) {rightBegin = size + 1;rightEnd = size;}else if (rightEnd >= size) {rightEnd = size - 1;}// 归并int j = leftBegin;while (leftBegin <= leftEnd && rightBegin <= rightEnd) {if (nums[leftBegin] < nums[rightBegin]) {temp[j++] = nums[leftBegin++];}else {temp[j++] = nums[rightBegin++];}}// 左区间还存在while (leftBegin <= leftEnd) {temp[j++] = nums[leftBegin++];}// 右区间还存在while (rightBegin <= rightEnd) {temp[j++] = nums[rightBegin++];}}memcpy(nums, temp, sizeof(int) * size);gap *= 2;}free(temp);
}

总结:

  1. 时间复杂度 O ( N ∗ l o g N ) O(N*logN) O(NlogN)
  2. 空间复杂度 O ( N ) O(N) O(N)

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

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

相关文章

【C++】开源:Boost库常用组件配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Boost库常用组件配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c…

想学Python高级编程?必须了解这个小技巧:match-case!

大家好&#xff0c;这里是程序员晚枫&#xff0c;小破站/知乎/小红书/抖音都叫这个名字。 上次给大家分享了Python高级编程第一讲&#xff1a;从使用类型提示开始 &#xff1b;今天分享Python高级编程第二讲&#xff1a;深入解析Python中switch case的使用方法。 写在前面 分…

巧用NGINX配置解决跨域问题

页面nginx配置 1&#xff0c;前端页面放在域名根目录&#xff0c;比如&#xff0c;http://www.xuecheng.com/ &#xff0c;对应的nginx配置&#xff1a; #门户location / {alias D:/Z_lhy/SpringCloud/xuecheng_online/www/xc-ui-pc-static-portal/;index index.html;} 页…

基于STM32设计的人体健康检测仪

一、项目介绍 当前文章介绍基于STM32设计的人体健康检测仪。设备采用STM32系列MCU作为主控芯片&#xff0c;配备血氧浓度传感器&#xff08;使用MAX30102血氧浓度检测传感器&#xff09;、OLED屏幕和电池供电等外设模块。设备可以广泛应用于医疗、健康等领域。可以帮助医生和病…

平板光波导中导模的(注意不是泄露模)传播常数β的matlab计算(验证了是对的)

参照的是导波光学_王建(清华大学)的公式(3-1-2、3-1-3)&#xff0c;算的参数是这本书的图3-3的。 function []PropagationConstantsMain() clear;clc;close all lambda01.55;%真空或空气中的入射波长&#xff0c;单位um k02*pi/lambda0; m3;%导模阶数(需要人为指定) n11.62;%芯…

网络知识点之-路由

本文章收录至《网络》专栏&#xff0c;点击右上角专栏图标可访问本专栏&#xff01; 路由&#xff08;routing&#xff09;是指分组从源到目的地时&#xff0c;决定端到端路径的网络范围的进程。路由工作在OSI参考模型第三层——网络层的数据包转发设备。路由器通过转发数据包来…

MySQL数据库配置及创建用户和授权

注意&#xff1a; 都是基于MySQL8.0以上版本 1、检查是否安装过sql [rootlocalhost ~]# rpm -[qa](https://so.csdn.net/so/search?qqa&spm1001.2101.3001.7020) | grep mysql[rootlocalhost ~]# rpm -qa | grep [mariadb](https://so.csdn.net/so/search?qmariadb&…

Spark(37):Streaming DataFrame 和 Streaming DataSet 创建

目录 0. 相关文章链接 1. 概述 2. socket source 3. file source 3.1. 读取普通文件夹内的文件 3.2. 读取自动分区的文件夹内的文件 4. kafka source 4.1. 导入依赖 4.2. 以 Streaming 模式创建 Kafka 工作流 4.3. 通过 Batch 模式创建 Kafka 工作流 5. Rate Source…

随笔03 考研笔记整理

图源&#xff1a;文心一言 上半年的博文整理&#xff0c;下半年依然会更新考研类的文章&#xff0c;有需要的小伙伴看向这里~~&#x1f9e9;&#x1f9e9; 另外&#xff0c;这篇文章可能是我上半年的努力成果之一&#xff0c;因此仅关注博主的小伙伴能够查看它~~&#x1f9e…

嵌入式系统中的GPIO控制:从理论到实践与高级应用

本文将探讨嵌入式系统中的GPIO(通用输入输出)控制,着重介绍GPIO的原理和基本用法。我们将使用一个实际的示例项目来演示如何通过编程配置和控制GPIO引脚。将基于ARM Cortex-M微控制器,并使用C语言进行编写。 GPIO是嵌入式系统中最常见且功能最强大的接口之一。它允许硬件工…

基于RK3588+FPGA+AI算法定制的智慧交通与智能安防解决方案

随着物联网、大数据、人工智能等技术的快速发展&#xff0c;边缘计算已成为当前信息技术领域的一个热门话题。在物联网领域&#xff0c;边缘计算被广泛应用于智慧交通、智能安防、工业等多个领域。因此&#xff0c;基于边缘计算技术的工业主板设计方案也受到越来越多人的关注。…

linux 指令 第3期

cat cat 指令&#xff1a; 首先我们知道一个文件内容属性 我们对文件操作就有两个方面&#xff1a;对文件内容和属性的操作 扩展&#xff1a;echo 指令 直接打印echo后面跟的字符串 看&#xff1a; 这其实是把它打印到了显示器上&#xff0c;我们也可以改变一下它的打印位置…

网络层中一些零碎且易忘的知识点

异构网络&#xff1a;指传输介质、数据编码方式、链路控制协议以及数据单元格式和转发机制不同&#xff0c;异构即物理层和数据链路层均不同RIP、OSPF、BGP分别是哪一层的协议&#xff1a; -RIPOSPFBGP所属层次应用层网络层应用层封装在什么协议中UDPIPTCP 一个主机可以有多个I…

Bootloader

Bootloader 一段有下载和引导功能的程序 下载应用程序引导使MCU运行在应用程序中&#xff0c;只在有更新请求或者APP无效的时候才会激活 APP和Bootloader都存在Flash中Flash Driver用来擦除APP&#xff0c;下载临时存放在RAM中&#xff0c;下载完成后复位释放。一般随用随下&a…

Pytorch个人学习记录总结 玩俄罗斯方块の深度学习小项目

目录 前言 模型成果演示 训练过程演示 代码实现 deep_network tetris test train 前言 当今&#xff0c;深度学习在各个领域展现出了惊人的应用潜力&#xff0c;而游戏开发领域也不例外。俄罗斯方块作为经典的益智游戏&#xff0c;一直以来深受玩家喜爱。在这个项目中&…

Python web实战 | 用 Flask 框架快速构建 Web 应用【实战】

概要 Python web 开发已经有了相当长的历史&#xff0c;从最早的 CGI 脚本到现在的全栈 Web 框架&#xff0c;现在已经成为了一种非常流行的方式。 Python 最早被用于 Web 开发是在 1995 年&#xff08;90年代早期&#xff09;&#xff0c;当时使用 CGI 脚本编写动态 Web 页面…

spring启动流程 (6完结) springmvc启动流程

SpringMVC的启动入口在SpringServletContainerInitializer类&#xff0c;它是ServletContainerInitializer实现类(Servlet3.0新特性)。在实现方法中使用WebApplicationInitializer创建ApplicationContext、创建注册DispatcherServlet、初始化ApplicationContext等。 SpringMVC…

68. 文本左右对齐

题目链接&#xff1a;力扣 解题思路&#xff1a;遍历单词数组&#xff0c;确定每一行的单词数量&#xff0c; 之后就可以得到每一个需要补充的空格数量。从而得到单词之间需要补充的空格数量。具体算法如下&#xff1a; 确定每一行的单词数量 初始值&#xff1a; num 0&…

【JavaWeb】正则表达式

&#x1f384;欢迎来到边境矢梦的csdn博文&#xff0c;本文主要讲解Java 中正则表达式 的相关知识&#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一下&#x1faf0;&#x1faf0;&am…

2023年的深度学习入门指南(22) - 百川大模型13B的运行及量化

2023年的深度学习入门指南(22) - 百川大模型13B的运行及量化 不知道上一讲的大段代码大家看晕了没有。但是如果你仔细看了会发现&#xff0c;其实代码还是不全的。比如分词器我们就没讲。 另外&#xff0c;13B比7B的改进点也没有讲。 再有&#xff0c;对于13B需要多少显存我们…