常见排序集锦-C语言实现数据结构

目录

排序的概念

常见排序集锦

     1.直接插入排序

     2.希尔排序

     3.选择排序

     4.堆排序

     5.冒泡排序

     6.快速排序

            hoare 

            挖坑法

            前后指针法

            非递归

     7.归并排序

            非递归

排序实现接口

算法复杂度与稳定性分析


排序的概念
      排序 :所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
    

这里推荐一个网站 数据结构和算法动态可视化 (Chinese) - VisuAlgo

它可以让我们更加清晰的看清楚排序的过程。

排序实现接口

                                                                 sort.h

#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<time.h>// 插入排序
void InsertSort(int* a, int n);// 希尔排序
void ShellSort(int* a, int n);// 选择排序
void SelectSort(int* a, int n);// 堆排序
void AdjustDwon(int* a, int n, int root);
void HeapSort(int* a, int n);// 冒泡排序
void BubbleSort(int* a, int n)// 快速排序递归实现// 1.快速排序hoare版本
int PartSort1(int* a, int left, int right);// 2.快速排序挖坑法
int PartSort2(int* a, int left, int right);// 3.快速排序前后指针法
int PartSort3(int* a, int left, int right);void QuickSort(int* a, int left, int right);// 快速排序 非递归实现
void QuickSortNonR(int* a, int left, int right)// 归并排序递归实现
void MergeSort(int* a, int n)// 归并排序非递归实现
void MergeSortNonR(int* a, int n)

                                            

1.插入排序

思想:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列

实现:
void InsertSort(int* arr, int n)
{// i< n-1 最后一个位置就是 n-2for (int i = 0; i < n - 1; i++){//[0,end]的值有序,把end+1位置的值插入,保持有序int end = i;int tmp = arr[end + 1];while (end >= 0){if (tmp < arr[end]){arr[end + 1] = arr[end];end--;}else{break;}}arr[end + 1] = tmp; // why?  end+1 //break 跳出 插入 因为上面end--;//为什么不在else那里插入?因为极端环境下,假设val = 0,那么end-- 是-1,不进入while , //所以要在外面插入}
}

为什么这里 for 循环 i < n-1 ? 如图所示:


2.希尔排序

希尔排序又称缩小增量法,思想 :算法先将要排序的一组数按某个增量 gap 分成若干组,每组中记录的下标相差 gap .对每组中全部元素进行排序,然后再用一个较小的增量对它进行分组,在每组中再进行排序。当增量减到1时( == 直接插入排序),整个要排序的数被分成一组,排序完成。

希尔排序可以理解为两个步骤:1.预排序 2.直接插入排序

 

如下图:

 实现:①

void ShellSort(int* arr, int n)
{int gap = n;while (gap > 1){gap = gap / 3 + 1;  //gap = gap / 2;for (int j = 0; j < gap; j++){for (int i = j; i < n - gap; i = i + gap){int end = i;int tmp = arr[end + gap];while (end >= 0){if (tmp < arr[end]){arr[end + gap] = arr[end];end = end - gap;}else{break;}}arr[end + gap] = tmp;}}
}

②:在①的基础上进行简单的优化

void ShellSort(int* arr, int n)
{//gap > 1 时 ,预排序//gap = 1 时,直接插入排序int gap = n;while (gap > 1){gap = gap / 3 + 1;  //加1意味着最后一次一定是1 ,当gap = 1 时,就是直接排序//gap = gap / 2;for (int i = 0; i < n - gap; i++){int end = i;int tmp = arr[end + gap];while (end >= 0){if (tmp < arr[end]){arr[end + gap] = arr[end];end = end - gap;}else{break;}}arr[end + gap] = tmp;}}}
为什么for循环内,i < n-gap  ?

 

gap的取值?

这里看个人习惯,上述中是gap一开始为n,进入循环后每次 /3 ,之所以+1是为了保证最后一次循环gap一定为1。当然 /2 也是可以的,/2 就可以最后不用+1。

希尔排序的特性总结:

1. 希尔排序是对直接插入排序的优化。
2. gap > 1 时都是预排序,目的是让数组更接近于有序。当 gap == 1 时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。
3. 希尔排序的时间复杂度不好计算,因为 gap 的取值方法很多,导致很难去计算,希尔排序的时间复杂度都不固定。
4.排升序,gap 越大,大的数更快到后面,小的数可以更快到前面,但是越不接近有序
                  gap越小,越接近有序 ,当gap = 1 时,就是直接插入排序。

3.选择排序

思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

实现:这里简单做了一下优化,每次遍历不仅仅选出最小的,也选出最大的。

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}void SelectSort(int* arr, int n)
{assert(arr);int left = 0; //开始位置int right = n - 1; //结束位置while (left < right){int min = left;int max = left;for (int i = left + 1; i <= right; i++){if (arr[i] < arr[min])min = i;if (arr[i] > arr[max])max = i;}Swap(&arr[left], &arr[min]);//如果 left 和 max 重叠 ,那么要修正 max 的位置if (left == max){max = min;}Swap(&arr[right], &arr[max]);left++;right--;}}


4.堆排序

思想:堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

 

实现:建堆方式有两种,这里采用向下调整方式建堆

typedef int HPDataType;void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustDown(HPDataType* arr, int size, int parent)//向下调整
{int child = parent * 2 + 1;while (child < size){if (arr[child + 1] > arr[child] && child + 1 < size){child++;}if (arr[child] > arr[parent]){Swap(&(arr[child]), &(arr[parent]));parent = child;child = (parent * 2) + 1;}else{break;}}}void HeapSort(int* arr, int n)
{//建堆for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(arr, n, i);}//排序int end = n - 1;while (end > 0){Swap(&(arr[0]), &(arr[end]));AdjustDown(arr, end, 0);end--;}}


5.冒泡排序

思想:根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,冒泡排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

可参考:冒泡

实现:

void BubbleSort(int* arr, int n)
{assert(arr);for (int i = 0; i < n; i++){int flag = 1;for (int j = 0; j < n - i - 1; j++){if (arr[j] > arr[j + 1]){Swap(&arr[j], &arr[j + 1]);flag = 0;}}//如果没有发生交换,说明有序,直接跳出if (flag == 1)break;}}


6.快速排序

思想:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止

hoare版本

 

 

 方法如下:

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}int PartSort1(int* arr, int begin, int end)
{int left = begin;int right = end;//keyi 意味着保存的是 key 的位置int keyi = left;while (left < right){//右边先走,找小while (left < right && arr[right] >= arr[keyi]){right--;}//左边再走,找大while (left < right && arr[left] <= arr[keyi]){left++;}//走到这里意味着,右边的值比 key 小,左边的值比 key 大Swap(&arr[left], &arr[right]);}//走到这里 left 和 right 相遇 Swap(&arr[keyi], &arr[left]);keyi = left; //需要改变keyi的位置return keyi;
}

挖坑法

 

 方法如下:

int PartSort2(int* arr, int begin, int end)
{int key = arr[begin];int piti = begin;while (begin < end){//右边先走,找小,填到左边的坑里去,这个位置形成新的坑while (begin < end && arr[end] >= key){end--;}arr[piti] = arr[end];piti = end;//左边再走,找大while (begin < end && arr[begin] <= key){begin++;}arr[piti] = arr[begin];piti = begin;}//相遇一定是在坑位arr[piti] = key;return piti;}

前后指针法

 方法如下:

int PartSort3(int* arr, int begin, int end)
{int key = begin;int prev = begin;int cur = begin + 1;//优化-三数取中int midi = GetMidIndex(arr, begin, end);Swap(&arr[key], &arr[midi]);while (cur <= end){if (arr[cur] < arr[key] && prev != cur ){prev++;Swap(&arr[prev], &arr[cur]);}cur++;}Swap(&arr[key], &arr[prev]);key = prev;return key;
}

实现:以上三种方法都是采用函数的方式实现,这样方便调用。另外,以上方法都是单趟排序,如果要实现完整的排序还是要采用递归的方法,类似于二叉树的前序遍历

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}void QuickSort(int* arr, int begin,int end)
{//当区间不存在或者区间只要一个值,递归返回条件if (begin >= end){return;}if (end - begin > 20) //小区间优化一般在十几{//int keyi = PartSort1(arr, begin, end);//int keyi = PartSort2(arr, begin, end);int keyi = PartSort3(arr, begin, end);//[begin , keyi - 1] keyi [keyi + 1 , end]//如果 keyi 的左区间有序 ,右区间有序,那么整体就有序QuickSort(arr, begin, keyi - 1);QuickSort(arr, keyi + 1, end);}else{InsertSort(arr + begin, end - begin + 1);//为什么+begin,因为排序不仅仅排序左子树,还有右子树//为什么+1 ,因为这个区间是左闭右闭的区间.例:0-9 是10个数 所以+1}
}

优化:

1. 三数取中法选key
2. 递归到小的子区间时,可以考虑使用插入排序(已在实现中使用)
int GetMidIndex(int* arr, int begin, int end)
{//begin   mid    endint mid = (begin + end) / 2;if (arr[begin] < arr[mid]){if (arr[mid] < arr[end]){return mid;}else if(arr[begin] < arr[end])  //走到这里说明 mid 是最大的{return end;}else{return begin;}}else // arr[begin] > arr[mid]{if (arr[mid] > arr[end]){return mid;}else if (arr[begin] < arr[end])  // 走到这里就是 begin end 都大于 mid{return begin;}else{return end;}}
}

非递归版本

非递归版本需要用到栈,这里是用c语言实现,所以需要手动实现一个栈

如果使用c++的话,可以直接引用栈。

这里栈的实现暂时省略,后期会给出链接。这里暂时知道一下就行。

 简图:

//非递归
//递归问题:极端场景下,深度太深,会出现栈溢出
//1.直接改成循环--例:斐波那契数列、归并排序
//2.用数据结构栈模拟递归过程
void QuickSortNonR(int* arr, int begin, int end)
{ST st;StackInit(&st);StackPush(&st, end);StackPush(&st, begin);while (!StackEmpty(&st)){int left = StackTop(&st);StackPop(&st);int right = StackTop(&st);StackPop(&st);int keyi = PartSort3(arr, left, right);//[left , keyi - 1]   keyi    [keyi + 1 , right]if (keyi + 1 < right){StackPush(&st, right);StackPush(&st, keyi + 1);}if (left < keyi - 1){StackPush(&st, keyi - 1);StackPush(&st, left);}}StackDestory(&st);
}


7.归并排序

思想:归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:

 实现:

void _MergeSort(int* arr, int begin, int end, int* tmp)
{if (begin >= end)return;int mid = (begin + end) / 2;//[begin mid]  [mid+1,end]//递归_MergeSort(arr, begin, mid, tmp);_MergeSort(arr, mid + 1, end, tmp);//归并[begin mid]  [mid+1,end]int left1 = begin;int right1 = mid;int left2 = mid + 1;int right2 = end;int i = begin;//这里之所以等于begin 而不是等于0 是因为可能是右子树而不是左子树 i为tmp数组下标while (left1 <= right1 && left2 <= right2){if (arr[left1] < arr[left2]){tmp[i++] = arr[left1++];}else{tmp[i++] = arr[left2++];}}//假如一个区间已经结束,另一个区间直接拿下来while (left1 <= right1){tmp[i++] = arr[left1++];}while (left2 <= right2){tmp[i++] = arr[left2++];}//把归并的数据拷贝回原数组 [begin mid]  [mid+1,end]// +begin 是因为可能是右子树    例:[2,3][4,5]//+1 是因为是左闭右闭的区间 0-9 是10个数据memcpy(arr + begin, tmp + begin, (end - begin + 1) * sizeof(int));}void MergeSort(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc");exit(-1);}_MergeSort(arr, 0, n - 1, tmp);free(tmp);
}

 

非递归版本:

思想:这里不能使用栈或者队列,因为栈或者队列适合前序遍历的替换,但是归并排序的思想属于后序遍历,栈和队列的特性导致后期可能无法使用前面的空间。

        这里因为是循环,所以可以设计一个变量 gap,当gap= 1 ,就一一进行归并,当gap = 2时,就两两进行归并,gap 每次 *2 。

如图:

 代码如下:

void MergeSortNonR(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc");exit(-1);}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){//[i , i + gap-1]  [i + gap , i + 2*gap-1]int left1 = i;int right1 = i + gap - 1;int left2 = i + gap;int right2 = i + 2 * gap - 1;int j = left1;while (left1 <= right1 && left2 <= right2){if (arr[left1] < arr[left2]){tmp[j++] = arr[left1++];}else{tmp[j++] = arr[left2++];}}while (left1 <= right1){tmp[j++] = arr[left1++];}while (left2 <= right2){tmp[j++] = arr[left2++];}}memcpy(arr, tmp, sizeof(int) * n);gap *= 2;}free(tmp);
}

       但是上述代码涉及到一个问题,因为假设要排序的数据不是2的次方倍就会产生问题(和数据的奇偶无关),就会越界

例:

 所以我们需要对代码进行优化, 优化可以从两个方面进行:    

//1.归并完成全部拷贝回原数组
//采用修正边界的方法
//例:如果是9个数据 最后一个数据也要继续进行归并
//因为如果不归并的话,最后一次会全部拷贝回原数组,也就意味着9个数据,前8个归并,拷贝回去的最后一个数据因为没有进行归并而产生随机值。

//如果越界,就修正边界,继续进行归并

代码如下:

void MergeSortNonR(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc");exit(-1);}int gap = 1;while (gap < n){//printf("gap=%d->", gap);for (int i = 0; i < n; i += 2 * gap){//[i , i + gap-1]  [i + gap , i + 2*gap-1]int left1 = i;int right1 = i + gap - 1;int left2 = i + gap;int right2 = i + 2 * gap - 1;//监测是否出现越界//printf("[%d,%d][%d,%d]---", left1, right1, left2, right2);//修正边界if (right1 >= n){right1 = n - 1;//[left2 , right2] 修正为一个不存在的区间left2 = n;right2 = n - 1;}else if (left2 >= n){left2 = n;right2 = n - 1;}else if (right2 >= n){right2 = n - 1;}//printf("[%d,%d][%d,%d]---", left1, right1, left2, right2);int j = left1;while (left1 <= right1 && left2 <= right2){if (arr[left1] < arr[left2]){tmp[j++] = arr[left1++];}else{tmp[j++] = arr[left2++];}}while (left1 <= right1){tmp[j++] = arr[left1++];}while (left2 <= right2){tmp[j++] = arr[left2++];}}//printf("\n");memcpy(arr, tmp, sizeof(int) * n);gap *= 2;}free(tmp);
}

2.归并一组数据就拷贝一组数据回原数组

这样,如果越界就直接break跳出循环,后面的数据不进行归并。

void MergeSortNonR_2(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc");exit(-1);}int gap = 1;while (gap < n){for (int i = 0; i < n; i += 2 * gap){//[i , i + gap-1]  [i + gap , i + 2*gap-1]int left1 = i;int right1 = i + gap - 1;int left2 = i + gap;int right2 = i + 2 * gap - 1;//right1 越界 或者 left2 越界,则不进行归并if (right1 >= n || left2 > n){break;}else if (right2 >= n){right2 = n - 1;}int m = right2 - left1 + 1;//实际归并个数int j = left1;while (left1 <= right1 && left2 <= right2){if (arr[left1] < arr[left2]){tmp[j++] = arr[left1++];}else{tmp[j++] = arr[left2++];}}while (left1 <= right1){tmp[j++] = arr[left1++];}while (left2 <= right2){tmp[j++] = arr[left2++];}memcpy(arr+i, tmp+i, sizeof(int) * m);}gap *= 2;}free(tmp);
}

以上两种方式的代码皆可,具体重要的还是思想。


算法复杂度与稳定性分析

       稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次 序保持不变,即在原序列中,r[i]=r[j],且r[i]r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排 序算法是稳定的;否则称为不稳定的。

 

 

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

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

相关文章

【计算机网络】13、ARP 包:广播自己的 mac 地址和 ip

机器启动时&#xff0c;会向外广播自己的 mac 地址和 ip 地址&#xff0c;这个即称为 arp 协议。范围是未经过路由器的部分&#xff0c;如下图的蓝色部分&#xff0c;范围内的设备都会在本地记录 mac 和 ip 的绑定信息&#xff0c;若有重复则覆盖更新&#xff08;例如先收到 ma…

ESP32+VSCode开发环境搭建(全网最强最终解决方案)

文章目录 1 安装步骤2 开发机器环境准备3 安装ESP-IDF-tools离线包4 创建VSCode配置文件(纯净的开发环境)5 安装espressif IDF 插件6 程序测试7 常见问题7.1环境变量设置问题&#xff1f;问题1&#xff1a;到底是设置IDF_TOOLS_PATH和IDF_PATH还是只配置一个IDF_TOOLS_PATH? 7…

Spring的简介ioc容器及注入方式

一.Spring的简介 1.Spring的特性 Spring是一个开源框架&#xff0c;它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。 Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。 然而&#xff0c;Spring的用途不仅限于服务器端的开发。从简单性、可测试性…

Python文件操作与输入输出:从基础到高级应用

文章目录 &#x1f340;引言&#x1f340;文件操作基础&#x1f340;上下文管理器与文件自动关闭&#x1f340;文件的迭代与逐行读取&#x1f340;文件的其他常见操作&#x1f340;输入输出基础&#x1f340; 文件输入输出&#x1f340;格式化输出&#x1f340;高级文件操作&am…

(二)掌握最基本的Linux服务器用法——Linux下简单的C/C++ 程序、项目编译

1、静态库与动态库 静态库(Static Library)&#xff1a;静态库是编译后的库文件&#xff0c;其中的代码在编译时被链接到程序中&#xff0c;因此它会与程序一起形成一个独立的可执行文件。每个使用静态库的程序都会有自己的库的副本&#xff0c;这可能会导致内存浪费。常用后缀…

AI 绘画Stable Diffusion 研究(九)sd图生图功能详解-老照片高清修复放大

大家好&#xff0c;我是风雨无阻。 通过前面几篇文章的介绍&#xff0c;相信各位小伙伴&#xff0c;对 Stable Diffusion 这款强大的AI 绘图系统有了全新的认知。我们见识到了借助 Stable Diffusion的文生图功能&#xff0c;利用简单的几个单词&#xff0c;就可以生成完美的图片…

7-3 求给定精度的简单交错序列部分和

分数 15 全屏浏览题目 切换布局 作者 C课程组 单位 浙江大学 本题要求编写程序&#xff0c;计算序列部分和 1 - 1/4 1/7 - 1/10 ... 直到最后一项的绝对值不大于给定精度eps。 输入格式: 输入在一行中给出一个正实数eps。 输出格式: 在一行中按照“sum S”的格式输出…

.net连接mysql,提示找不到请求的 .Net Framework Data Provider。可能没有安装

开发完成的.net程序需要连接mysql数据库&#xff0c;在个人电脑上运行没问题&#xff0c;别人运行时提示“提示找不到请求的 .Net Framework Data Provider。可能没有安装”。经过查询&#xff0c;安装Connector/NET 8.1.0&#xff0c;下载地址如下所示&#xff1a; https://d…

(分治) 剑指 Offer 16. 数值的整数次方 ——【Leetcode每日一题】

❓剑指 Offer 16. 数值的整数次方 难度&#xff1a;中等 实现 pow(x, n) &#xff0c;即计算 x 的 n 次幂函数&#xff08;即&#xff0c; x n x^n xn&#xff09;。不得使用库函数&#xff0c;同时不需要考虑大数问题。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n …

腾讯云轻量服务器测评:2核 2G 4M

腾讯云轻量2核2G4M服务器&#xff0c;4M带宽下载速度可达512KB/秒&#xff0c;系统盘为50GB SSD盘&#xff0c;300GB月流量&#xff0c;地域节点可选上海、广州和北京&#xff0c;腾讯云百科分享腾讯云2核2G4M轻量应用服务器配置性能表&#xff1a; 目录 腾讯云轻量2核2G4M服…

谈谈网络协议的定义、组成和重要性

个人主页&#xff1a;insist--个人主页​​​​​​ 本文专栏&#xff1a;网络基础——带你走进网络世界 本专栏会持续更新网络基础知识&#xff0c;希望大家多多支持&#xff0c;让我们一起探索这个神奇而广阔的网络世界。 目录 一、网络协议的定义 二、网络协议的组成 1、…

Vite更新依赖缓存失败,强制更新依赖缓存

使用vitets开发一段时间了&#xff0c;感觉并不是想象中的好用&#xff0c;特别是出现些稀奇古怪的问题不好解决&#xff0c;比如下面这个问题 上午9:50:08 [vite] error while updating dependencies: Error: ENOENT: no such file or directory, open E:/workspace-dir/node…

常见期权策略类型有哪些?

这几天在做一个期权策略类型的整理分类&#xff0c;怎么解释期权策略&#xff0c;期权策略是现代金融市场中运用非常广泛、变化非常丰富、结构非常精妙的金融衍生产品&#xff1b;同时也是一种更为复杂也更为灵活的投资工具&#xff0c;下文介绍常见期权策略类型有哪些&#xf…

区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归时间序列区间预测

区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 MATLAB实现QRLSTM长短期记忆神经网络分位数回归时间序…

【Git】(四)子模块

1、增加子模块 进入准备添加子模块所在的目录&#xff0c;例如library。 git submodule add -b 1.0.0.0 gitgitee.com:sunriver2000/SubModule.git参数-b用于指定子模块分支。 2、更新子模块 git submodule update --progress --init --recursive --force --remote -- "…

[Go版]算法通关村第十一关白银——位运算的高频算法题

目录 专题1&#xff1a;位移的妙用题目&#xff1a;位1的个数&#xff08;也被称为汉明重量&#xff09;解法1&#xff1a;遍历所有位&#xff0c;判断每个位的数字是否是1Go代码 解法2&#xff1a;依次消除每个1的位 numnum&(num-1)Go代码 题目&#xff1a;比特位计数思路…

【数据结构】树和二叉树的概念及结构

1.树概念及结构 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有一个特殊的结点&#…

迅捷视频工具箱:多功能音视频处理软件

这是一款以视频剪辑、视频转换、屏幕录像等特色功能为主&#xff0c;同时附带有视频压缩、视频分割、视频合并等常用视频处理功能为主的视频编辑软件。该软件操作简单易用&#xff0c;即使没有视频处理经验的用户也可以轻松上手。将视频添加到工具箱对应功能后&#xff0c;简单…

腾讯云3年轻量应用服务器2核4G5M和2核2G4M详细介绍

腾讯云轻量应用服务器3年配置&#xff0c;目前可以选择三年的轻量配置为2核2G4M和2核4G5M&#xff0c;2核2G4M和2核4G5M带宽&#xff0c;当然也可以选择选一年&#xff0c;第二年xufei会比较gui&#xff0c;腾讯云百科分享腾讯云轻量应用服务器3年配置表&#xff1a; 目录 腾…

javaScript:数组检测

目录 一.前言 二.数组检测方法 1.every&#xff08;&#xff09; 2.some&#xff08;&#xff09; 3.filter&#xff08;&#xff09; 一.前言 数组检测是指在编程中对数组进行验证和检查的过程。数组检测可以涉及以下方面&#xff1a; 确定数组的存在&#xff1a;在使用数…