(数据结构)八大排序算法

目录

  • 一、常见排序算法
  • 二、实现
    • 1. 直接插入排序
    • 2.🌟希尔排序
    • 3. 选择排序
    • 4.🌟堆排序
    • 5. 冒泡排序
    • 7. 🌟快速排序
      • 7.1 其他版本的快排
      • 7.2 优化
      • 7.3 ⭐非递归
    • 7. 🌟归并排序
      • 7.1 ⭐非递归
    • 8. 计数排序
  • 三、总结
    • 1. 分析

  排序 (Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个 数据元素 (或记录)的任意序列,重新排列成一个关键字有序的序列。

一、常见排序算法

在这里插入图片描述

二、实现

1. 直接插入排序

介绍:将待排的数,和有序的数比较,直到一个合适的位置,然后进行插入。

示图在这里插入图片描述

将待排数4,与有序数对比,然后插入到(比4小的数)2前面

代码

// 插入排序(升序)
void InsertSort(int* a, int n)
{
	for (int i = 0; i < n-1 ; ++i)
	{
		int end = i;
        //[0,end]为有序数组
        
        //记录下需要插入的数,将end+1的位置空出来
		int temp = a[end + 1];
        //将需插入的数和有序数组对比
		while (end >= 0)
		{
            //如果大于,则向后移动一位
			if (a[end] > temp)
			{
				a[end + 1] = a[end];
				end--;
			}
			else//否则,退出
			{
				break;
			}
		}
        //下标(end+1)就是合适的插入位置
		a[end + 1] = temp;
	}
}

效率:时间复杂度为 O ( N 2 ) O(N^2) O(N2)

如果原始数组为升序有序,则直接会break,时间复杂度为 O ( N ) O(N) O(N)


2.🌟希尔排序

介绍:利于直接插入排序的思想,如果所排的数据接近有序,则排序效率非常高。希尔排序,是将数据非为若干组,然后对每组的数据进行插入排序,使之逐渐有序。

其中如果分组为1,则等于直接插入排序

图示在这里插入图片描述

将数据分为9 5 8 13 2 7两组,分别进行插入排序,得到1 2 5 3 8 7 9,逐渐接近有序

代码

void Swap(int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}
// 希尔排序(升序)
void ShellSort(int* a, int n)
{
	int group = n;
    //逐渐将分组缩小,直至分组为1
	while (group > 1)
	{
        //一般分组每次缩小1/3
        //+1:为确保最后分组为1
		group = group / 3 + 1;
        //每个数依次在它所在组中插入排序
		for (int i = 0; i < n - group; i++)
		{
			int end = i;//每组排序好的最后一个元素
			int temp = a[end + group];//对应组下一个要插入的元素
            //思路同插入排序,只不过操作的是对应组中的元素
			while (end >= 0)
			{
				if (a[end] > temp)
				{
					a[end + group] = a[end];
					end -= group;
				}
				else
				{
					break;
				}
			}
			a[end + group] = temp;
		}
	}
}

效率:时间复杂度大约为 O ( N 1.3 ) O(N^{1.3}) O(N1.3)

因为希尔排序的时间复杂度非常难算,感兴趣的可以去百度。


3. 选择排序

介绍:每一次都遍历一遍数据,选出最小(大)的元素,放在起始点。

图示在这里插入图片描述

代码

// 选择排序(升序)
void SelectSort(int* a, int n)
{
	int begin = 0;
	int end = n - 1;
    //每遍历一遍,选出最大和最小
	while (begin < end)
	{
		int maxi = end;
		int mini = begin;
		for (int i = begin; i <= end; i++)
		{
			if (a[maxi] < a[i])
			{
				maxi = i;
			}
			if (a[mini] > a[i])
			{
				mini = i;
			}
		}
		Swap(&a[begin], &a[mini]);
        //如果最大的数下标为begin,被上一步改变
		if (maxi == begin)
		{
			maxi = mini;
		}
		Swap(&a[end], &a[maxi]);
        
		begin++;
		end--;
	}
}

效率:时间复杂度为 O ( N 2 ) O(N^2) O(N2)

虽然一次遍历找一个,优化为每趟找两个,只是每趟比较次数的等差数列的公差由1变为2,但是大 O O O的渐进表示法都为 O ( N 2 ) O(N^2) O(N2)


4.🌟堆排序

简介:该部分涉及堆的相关知识,

详情请见另一篇:堆

效率:时间复杂度为 O ( N l o g 2 N ) O(Nlog_2N) O(Nlog2N)


5. 冒泡排序

简介:冒泡的思想就是遍历数据进行比较,然后把最大(小)的数交换到最后位置。

图示在这里插入图片描述

代码

// 冒泡排序(升序)
void BubbleSort(int* a, int n)
{
	//最多要遍历n-1次
	for (int i = 0; i < n - 1; ++i)
	{
		int flag = 0;
		for (int j = 0; j < n - i - 1; ++j)
		{
            //当前的数与下一个数进行比较
			if (a[j] > a[j + 1])
			{
				Swap(&a[j], &a[j + 1]);
				flag = 1;
			}
		}
        
        //如果没有进行交互,则已经排序完成了
		if (flag == 0)
		{
			break;
		}
	}
}

效率:时间复杂度 O ( N 2 ) O(N^2) O(N2)

因为优化了退出条件,因此对于已排序的原始数据,时间复杂度为 O ( N ) O(N) O(N)


7. 🌟快速排序

简介:开始时,任取数据中的某一元素为基准,然后将小于该元素的放在左边,大于该元素的放在右边,把剩余数据分为两个序列。然后再对左右序列重复该过程,直到每个元素都在对应位置

(hoare版本)图示在这里插入图片描述

对数组4 3 6 7 2 1 5,以第一个4为关键数,升序排列,大于4的都放在右边,小于4的放在左边。得到结果2 3 1 4 6 7 5

先移动右指针,走到小于4的数停下,再移动左指针,找到大于4的数停下,交换两数,然后继续,直到左右指针相遇,因为左指针后走,因此停下的位置一定是小于等于4的,再和4交换。

代码

void QuickSort(int* a, int left, int right)
{
    //如果只有一个数,直接返回
	if (left >= right)
	{
		return;
	}
    //记录起始和结束
    int begin = left;
	int end = right;
	//默认key为第一个数
	int keyi = left;
	while (left < right)
	{
        //先移动右指针,找到比key小的数
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
        //再移动左指针,找到比key大的数
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
    //right位置一定小于等于keyi位置数据
	Swap(&a[right], &a[keyi]);
    keyi = right;
	//分别排左右序列
    //[left,keyi-1], keyi, [keyi-1,right]
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1, end);
}

效率:时间复杂度 O ( N l o g 2 N ) O(Nlog_2N) O(Nlog2N)。每次走一趟,一共走 l o g 2 N log_2N log2N

7.1 其他版本的快排

挖坑法
在这里插入图片描述

void QuickSort(int* a, int left, int right)
{
	if (left >= right) return;

    int begin = left, end = right;
    
    //默认key为第一个数
	int key = a[left];
	int piti = left;//坑的位置
    
	while (left < right)
	{
        //右指针先走
		while (left < right && a[right] >= key)
		{
			--right;
		}
		a[piti] = a[right];
		piti = right;
        //左指针走
		while (left < right && a[left] <= key)
		{
			++left;
		}
		a[piti] = a[left];
		piti = left;
	}
    //最后留下的坑位来存放key
	a[piti] = key;

    QuickSort(a, begin, keyi - 1);
    QuickSort(a, keyi + 1, end);	
}

前后指针在这里插入图片描述

  用cur来找到小于key的元素,prev找到大于key的元素。刚开始时,cur还未遇见大于等于key的元素时,cur和prev一起向右。(如果此步,不好理解的话,可以自己动手画画)

void QuickSort(int* a, int left, int right)
{
	if (left >= right) return;
    
	int begin = left, end = right;	
    
	int keyi = left; //默认key为第一个数
	int prev = left;
	int cur = left + 1;
    
	while (cur <= right)
	{
 //当cur小于key,且prev++后不等于cur,才会交换
		if (a[cur] < a[keyi] && ++prev!=cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		++cur;//cur一直向后走
	}
	Swap(&a[keyi], &a[prev]);
	keyi = prev;
    
    QuickSort(a, begin, keyi - 1);
    QuickSort(a, keyi + 1, end);
}

7.2 优化

三数取中

  因为key的选取会影响快速排序的效率,其中,如果key每次都是是中间的数,接近二分,效率最高 O ( N l o g 2 N ) O(Nlog_2N) O(Nlog2N);如果每次都是最小(大)的数,则效率最低 O ( N 2 ) O(N^2) O(N2),因为总会出现[key]+[未排序数据]​

//找到前中后三个数中,中间的那个
int GetMid(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[mid] < a[left])
	{
		if (a[right] > a[left])
		{
			return left;
		}
		else if (a[right] < a[mid])
		{
			return mid;
		}
		else
		{
			return right;
		}
	}
	else
	{
		if (a[right] < a[left])
		{
			return left;
		}
		else if (a[right] > a[mid])
		{
			return mid;
		}
		else
		{
			return right;
		}
	}
}

结合插入排序

对于一组比较大的数据,在递归后期,小范围的序列会有很多。因此可以在划分的范围足够小后,直接使用插入排序,避免继续向下递归。(tips:最后一次的递归次数占总递归次数的一半左右)

void QuickSort(int* a, int left, int right)
{
	if (left >= right)
	{
		return;
	}
	int keyi = left;
	int end = right;
    
    //三数取中
	int midi = GetMid(a, left, right);
	Swap(&a[midi], &a[keyi]);
    
    //使用插入排序
	if (right - left < 13)
	{
		InsertSort(a + left, right - left + 1);
	}
    else
    {
        int begin = left, end = right;
        
        while (left < right)
        {
            //先移动右指针,找到比key小的数
            while (left < right && a[right] >= a[keyi])
            {
                right--;
            }
            //再移动左指针,找到比key大的数
            while (left < right && a[left] <= a[keyi])
            {
                left++;
            }
            Swap(&a[left], &a[right]);
        }
        Swap(&a[right], &a[keyi]);
        keyi = right;
        
        QuickSort(a, begin, keyi - 1);
		QuickSort(a, keyi + 1, end);
    }
}

7.3 ⭐非递归

递归的思想,比较容易写,但是它占用栈区空间,如果数据足够大,是可能发生栈溢出错误的。

保持快速排序的思路不变,显然循环无法实现,但是我们可以用栈来模拟递归

每次将要比较的序列的范围[bigin,end],记录到栈中,每次循环开始,出栈,结束后又将新划分的左右序列入栈。

 快速排序 非递归实现
void QuickSortNonR(int* a, int left, int right)
{
	Stack st;
	StackInit(&st);
	StackPush(&st, left);
	StackPush(&st, right);
     
	while (!StackEmpty(&st))
	{
        //出栈,得到要排序的范围[bigin,end]
		int end = StackTop(&st);
		StackPop(&st);
		int begin = StackTop(&st);
		StackPop(&st);
		//排序,使key放到正确位置
        int keyi = begin;
        int prev = begin;
        int cur = begin + 1;
        while (cur <= end)
        {
            //当cur小于key,且prev++后不等于cur,才会交换
            if (a[cur] < a[keyi] && ++prev!=cur)
            {
                Swap(&a[cur], &a[prev]);
            }
            ++cur;//cur一直向后走
        }
        Swap(&a[keyi], &a[prev]);
        keyi = prev;
 //将新的左右序列[bigin,keyi-1],[keyi+1,end]入栈
		if (begin < keyi - 1)
		{
			StackPush(&st, begin);
			StackPush(&st, keyi - 1);
		}
		if (keyi + 1 < end)
		{
			StackPush(&st, keyi + 1);
			StackPush(&st, end);
		}
	}

	StackDestroy(&st);
}

同样的,其实可以用队列来实现快速排序的非递归。

思路:将bigen end入队列,循环开始时,出队列找到要排序的范围[begin,end],排序完成后将左右序列[bigin,keyi-1],[keyi+1,end]入队列

和栈实现不同的是:栈是以递归的方式,排完左序列后才会开始排右,而队列则是排左,排右交替进行。

7. 🌟归并排序

简介:采用分治实现,将数据划分为两等份分别有序的序列,然后合并。

图示在这里插入图片描述

对数据1 0 5 3 2,进行归并排序,首先将数据分为两份1 0 53 2,在向下划分,直至最小的,然后在将两两归并,逐渐形成有序序列。

代码

void _MergeSort(int* a, int n, int begin, int end, int* temp)
{
	if (begin >= end)
	{
		return;
	}
	int mid = (begin + end) / 2;
//由图示,可见,后序,深度优先
    //[begin,mid] [mid+1,end]
	_MergeSort(a, n, begin, mid, temp);
	_MergeSort(a, n, mid+1, end, temp);
	
//将[begin,mid] [mid+1,end]两个序列按顺序合并
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int i = begin;
	while (begin1 <= end1 && begin2 <= end2)
	{
				//   "<"升序
		if (a[begin1] < a[begin2])
		{
			temp[i++] = a[begin1++];
		}
		else
		{
			temp[i++] = a[begin2++];
		}
	}
	//处理某个序列的剩余数据
	while (begin1 <= end1)
	{
		temp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		temp[i++] = a[begin2++];
	}
	
	//拷贝到原数组中,也可以使用库函数	
//memcpy(a + begin, tmp + begin, (end - begin + 1)*sizeof(int));
	for (int j = begin; j <= end; ++j)
	{
		a[j] = temp[j];
	}

}

// 归并排序递归实现
void MergeSort(int* a, int n)
{
	//因为有两个序列归并一起,因此需要额外的空间存放,temp为额外空间
	int* temp = (int*)malloc(sizeof(int) * n);
	if (temp == NULL)
	{
		perror("malloc failed\n");
		exit(-1);
	}

	_MergeSort(a, n, 0, n - 1, temp);

	free(temp);
}

效率:时间复杂度 O ( N l o g 2 N ) O(Nlog_2N) O(Nlog2N)

严格的二分,会比快速排序更优,但是需要额外的空间 O ( N ) O(N) O(N)

7.1 ⭐非递归

递归,同样面临栈溢出的风险。

由归并排序的思想,先将数据划分为1个数一组的序列,然后将相邻的两个组合并,然后再分为2个数一组的序列,再进行合并,直到最后划分整个序列为一组。

  tips:由于是按照1,2,4,8…逐渐划分的,但是原始数据的长度可能并不是严格的 2 n 2^n 2n个,所有划分出的组可能会出现越界问题,需要处理。

代码

// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{
    //需要的额外空间
	int* temp = (int*)malloc(sizeof(int) * n);

	int grap = 1;//开始时一组有1个数
	while (grap < n)
	{
        //[j,j+grap-1] 与 [j+grap,j+2*grap-1] 按序合并
		for (int j = 0; j < n; j += grap*2)
		{
			int begin1 = j, end1 = j+grap-1;
			int begin2 = j + grap, end2 = j + 2 * gap - 1;
            
			//修正
            //end1数组越界
			if (end1 >= n)
			{
				end1 = n - 1;
				begin2 = n;
				end2 = n - 1;
			}
            //begin2数组越界
			else if (begin2 >= n)
			{
				begin2 = n;
				end2 = n - 1;
			}
            //end2数组越界
			else if (end2 >= n)
			{
				end2 = n - 1;
			}
            
			int i = begin1;
			while (begin1 <= end1 && begin2 <= end2)
			{
				//   "<"升序
				if (a[begin1] < a[begin2])
				{
					temp[i++] = a[begin1++];
				}
				else
				{
					temp[i++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				temp[i++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				temp[i++] = a[begin2++];
			}
		}

		//拷贝到原数组中
		memcpy(a, temp, sizeof(int)*n);
        //每次每组扩大2倍
		grap *= 2;
	}

	free(temp);
}

8. 计数排序

简介:因为数组下标为整数,因此对于整型数据,我们可以遍历一般然后计数,最后再遍历一般写入。

图示在这里插入图片描述

利用数组下标,来在该空间位置存放个数,然后在遍历数组,使之有序。但是适用范围有限。

代码

// 计数排序
void CountSort(int* a, int n)
{
    //找到数据中的max与min的数
	int max = a[0], min = a[0];
	for (int i = 1; i < n; ++i)
	{
		if (a[i] > max)
			max = a[i];
        
		if (a[i] < min)
			min = a[i];
	}
	//这所需开辟数组大小为
    //所开辟数组[0,range-1]
    //与原数据中[mini,maxi],构成映射
	int range = max - min + 1;
	int* count = (int*)calloc(range, sizeof(int));
	
    //计数
	for (int i = 0; i < n; ++i)
	{
		count[a[i]-min]++;
	}
    
    //进行排序
	int j = 0;
	for (int i = 0; i < range; ++i)
	{
		while (count[i]--)
		{
            //从映射中还原
			a[j++] = i + min;
		}
	}

	free(count);
}

效率:时间复杂度为 O ( N ) O(N) O(N)

三、总结

稳定性:对于原数据中,相同值、不同先后顺序的元素,进行排序后,如果其先后顺序任未改变,则称该排序算法是稳定的。

通常稳定主要用于对一组原始数据(每个元素有多个属性值),按照不同规律进行排序时才非常重要。

1. 分析

下面👇同种算法,时间复杂度最好或最坏的情况,其代码可能不同(有无优化)

排序算法平均时间复杂度最好最坏空间复杂度稳定性
直接插入排序 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
希尔排序 O ( n 1.3 ) O(n^{1.3}) O(n1.3) O ( n 1.3 ) O(n^{1.3}) O(n1.3) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)不稳定
选择排序 O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)不稳定
堆排序 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( 1 ) O(1) O(1)不稳定
冒泡排序 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n 2 ) O(n^2) O(n2) O ( 1 ) O(1) O(1)稳定
快速排序 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n 2 ) O(n^2) O(n2) O ( l o g 2 n ) O(log_2n) O(log2n)~ O ( n ) O(n) O(n)不稳定
归并排序 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g n ) O(nlog_n) O(nlogn) O ( n ) O(n) O(n)稳定
计数排序 O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( m a x ( n , r a n g e ) ) O(max(n,range)) O(max(n,range))

该总结,还是要结合前面详细的讲解,自己要能够分析出来。

🦀🦀观看~~

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

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

相关文章

网络安全的特性

0x00 前言 网络安全的特性包括&#xff0c;机密性&#xff0c;完整性&#xff0c;可用性&#xff0c;真实性和不可否认性。详细的内容可以参考如下的内容。 Xmind资源请下载~ 0x01 机密性 机密性&#xff08;Confidentiality&#xff09; 意味着阻止未经授权的实体&#x…

【springcloud 微服务】Spring Cloud Alibaba Sentinel使用详解

目录 一、前言 二、分布式系统遇到的问题 2.1 服务可用性问题 2.1.1 单点故障 2.1.2 流量飙升 2.1.3 容错机制 2.2 服务雪崩问题 三、 服务可用性解决方案 3.1 服务容错机制 3.1.1 超时机制 3.1.2 服务限流 3.1.3 隔离 3.2 服务熔断 3.2.1 什么是服务熔断 3…

springcloud学习总结

springcloud 构建微服务项目步骤 导入依赖编写配置文件开启这个功能 Enablexxx配置类 于2023年2月24日下午17点38分开始学习于2023年3月17日晚上20点26分学完总结代码地址&#xff1a;https://gitee.com/liang-weihao/StudySpringcloud学习笔记地址&#xff1a;https://www.…

JavaEE简单示例——基于注解的AOP实现

简单介绍&#xff1a; 之前我们介绍了关于XML的面向切面的编程&#xff0c;通过配置文件的方法&#xff0c;在不修改源代码的情况下完成了对已有方法的增强 除了基于XML配置文件的方式&#xff0c;我们还可以使用更简单的&#xff0c;基于注解的方式。 每一次&#xff0c;我们…

【DBC专题】-12-不同类型报文(应用/诊断/网关/测量标定)在DBC中配置,以及在Autosar各模块间的信号数据流向

点击返回「Autosar从入门到精通-实战篇」总目录 案例背景(共18页精讲)&#xff1a;该篇博文将告诉您&#xff1a; 1)Autosar中&#xff0c;不同类型报文(App应用&#xff0c;UDS/OBD诊断&#xff0c;NM网络管理报文&#xff0c;XCP测量标定)的信号数据流向&#xff1b; 2)CAN …

【IoT】嵌入式驱动开发:IIC子系统

IIC有三种接口实现方式 三种时序对比: 图1 IIC子系统组成 图2 图3 IIC操作流程 设备端 1.i2c_get_adapter 2.i2c_new_device(相当于register设备) 3.I2c_put_adapter 驱动端 1.填充i2c_driver 2.i2c_add_driver(相当于register驱动) 3.在probe中建立访问方式 client相…

蓝桥杯刷题冲刺 | 倒计时22天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;马上就要蓝桥杯了&#xff0c;最后的这几天尤为重要&#xff0c;不可懈怠哦&#x1f43e; 文章目录1.选数异或2.特殊年份1.选数异或 题目 链接&#xff1a; 选数异或 - 蓝桥云课 (lanqiao.cn) 给定…

C++修炼之筑基期第一层——认识类与对象

文章目录&#x1f337;专栏导读&#x1f337;什么是面向对象&#xff1f;&#x1f337;类的引入&#x1f337;什么是类&#x1f337;类的定义方式&#x1f337;类的访问限定符与封装&#x1f33a;访问限定符&#x1f33a;封装&#x1f337;类的作用域&#x1f337;类的实例化&a…

基于STM32的ADC采样及各式滤波实现(HAL库,含VOFA+教程)

前言&#xff1a;本文为手把手教学ADC采样及各式滤波算法的教程&#xff0c;本教程的MCU采用STM32F103ZET6。以HAL库的ADC采样函数为基础进行教学&#xff0c;通过各式常见滤波的实验结果进行分析对比&#xff0c;搭配VOFA工具直观的展示滤波效果。ADC与滤波算法都是嵌入式较为…

今天,我终于学懂了C++中的引用

文章目录一、前言二、概念介绍三、引用的五大特性1、引用在定义时必须初始化2、一个变量可以有多个引用3、一个引用可以继续有引用4、引用一旦引用一个实体&#xff0c;再不能引用其他实体5、可以对任何类型做引用【变量、指针....】四、引用的两种使用场景1、做参数a.案例一&a…

vue大型商城系统中遇到的问题(上)

一&#xff1a;创建仓库1.领导创建git仓库&#xff08;参考————这篇文章&#xff09;&#xff0c;新手下载git2.打开cmd终端&#xff0c;将git仓库拉到本地3.进入文件目录&#xff0c;查看分支&#xff08;新手向——为什么需要创建分支&#xff0c;查看---&#xff09;4.创…

SAP 发出商品业务配置

SAP发出商品业务配置&#xff0c;即&#xff1a; 出具销售发票时结转成本 一、业务背景&#xff1a; 发出商品业务简单的理解为跨月开票&#xff0c;即出库与开票不在同一个月份。 该业务在系统内的实现方式&#xff0c;为保证成本与收入的配比&#xff0c;在出库时不计算成…

JDBC概述

1.1 数据的持久化持久化(persistence)&#xff1a;把数据保存到可掉电式存储设备中以供之后使用。大多数情况下&#xff0c;特别是企业级应用&#xff0c;数据持久化意味着将内存中的数据保存到硬盘上加以”固化”&#xff0c;而持久化的实现过程大多通过各种关系数据库来完成。…

LeetCode-复制带随机指针的链表

题目描述&#xff1a; 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都设为其对应的…

蓝桥杯备赛 [day01]|python|迷宫问题|乘积尾零|平方和|切面条|付账问题

目录 0 题目类型 1 迷宫问题 图解 2 乘积尾零 算法解释 用Python处理大数 用C编码 3 平方和 解题技巧 4 切面条 算法解释 5 贪心问题——付账问题 ​编辑 思路 求解步骤 0 题目类型 (1)杂题。不需要算法和数据结构&#xff0c;只需要逻辑、推理的题目&#x…

C/C++每日一练(20230319)

目录 1. 反转链表 II &#x1f31f;&#x1f31f; 2. 解码方法 &#x1f31f;&#x1f31f; 3. 擅长编码的小k &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 …

解决win10任何程序打开链接仍然为老旧IE的顽固问题[修改默认浏览器]

文章目录一、问题与修改原因1、着手修改吧2、弯路上探索3、发现祸根二、后话文章原出处&#xff1a; https://blog.csdn.net/haigear/article/details/129344503一、问题与修改原因 我们发现&#xff0c;很多程序默认的网页打开浏览器都是IE&#xff0c;这个很是郁闷&#xff…

jira提交bug规范

一、目的 1&#xff09;方便开发人员根据bug描述快速进行定位问题原因&#xff0c;减少沟通成本。 2&#xff09;规范bug编写&#xff0c;可以提现测试团队的专业性、严谨性。 3&#xff09;可以帮助产品、项目经理及其它人员快速了解bug。 二、说明 本文档主要描述了技术产…

ThreadPool线程池源码解析

ThreadPool线程池源码解析 文章目录前言一、基本使用二、执行流程三、源码分析ThreadPoolExecutor 中重要属性ThreadPoolExecutor 内部类Workerexecute&#xff08;&#xff09;方法addWorker(command, true)方法runWorker(worker )方法getTask()方法shutdown和shutdownNow四、…

进阶C语言:指针的进阶(1)

关于指针这个概念从初识C语言就开始进行了解&#xff0c;一直到了进阶C语言&#xff0c;通过前面初识C语言和初阶C语言对指针的学习还是不够深入&#xff0c;所以在进阶中再来对指针进行深入的学习指针的主题&#xff1a;1. 指针就是个变量&#xff0c;用来存放地址&#xff0c…
最新文章