一篇博客读懂排序

目录

一、常见的排序

二、冒泡排序 

2.1基本思想:

2.2代码:

三、插入排序

3.1基本思想:

3.2思路讲解:

3.3代码:

3.4时间复杂度:

四、希尔排序

4.1基本思路:

4.2思路讲解:

4.3代码:

4.4时间复杂度:

五、选择排序

5.1基本思路:

5.2思路讲解:

5.3代码:

5.4时间复杂度:

六、堆排序

6.1基本思路:

6.2思路讲解:

6.3代码:

6.4时间复杂度:

七、快速排序(hoare版本)

7.1基本思路:

7.2思路讲解:

7.3代码:

7.4时间复杂度:

八、快速排序(挖坑法和前后指针版本)

8.1挖坑法

8.1.1挖坑法讲解

8.1.2代码:

 8.2前后指针版本

8.1.1前后指针讲解

8.1.2代码: 

九、归并排序 

9.1基本思路:

9.2思路讲解:

9.3代码:

9.4时间复杂度:


一、常见的排序

二、冒泡排序 

2.1基本思想:

冒泡排序,何为冒泡,即把数据最大的每次都排到最后一个位置,像冒泡一样。

2.2代码:

void BubbleSort(int* a, int n)
{
	int i = 0;
	
	for (; i < n; i++)
	{
		int j = 1;
		for (; j < n - i; j++)
		{
			if (a[i - 1] > a[i])
				Swap(&a[i - 1], &a[i]);
		}
	}
}

三、插入排序

3.1基本思想:

  把待排序的数据逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

3.2思路讲解:

以上图数据、升序为例。
为了便于理解,我们分为两大阵营,已排和未排。我们在没排序之前,这些数据全都是未排阵营,接着我们开始比较,由于已排阵营没有数据,所以9就是第一个。然后拿未排阵营的33和9比较,33放在9之后。
接着就是10和33比较,10放在33前;10和9排序,10放在9后,此趟结束。

46和33比较,46放在33后,此趟结束。

23和46比较,放在46前;23和33比较,放在33前;23和10比较,放在10后,此趟结束。

我相信说了这几趟,大家就能基本明白,插入排序就是把没排序的和已排序的从后向前依次比较然后找到不满足条件的位置把自己放进去。

3.3代码:

首先,我们先完成单趟排序。
然后,我们介绍一下需要新引入的变量:

其中,因为我们需要把数组看成两部分,所以我们引入end作为两者的分界点;当挪动数据时,我们用前一个数据覆盖后一个数据,所以需要tmp记录被覆盖元素的值,即当前插入的元素。
当我们的插入元素不满足条件时,即它在前后两个元素之间,此时end移动到了前一个元素,所以后来我们需要把end+1赋值为插入的数值:

void InsertSort(int arr[], int n)
{
	int end = 0;
	int tmp = arr[end + 1];
	
	while (end >= 0)
	{
		if (arr[end] > tmp)
		{
			arr[end + 1] = arr[end]; 
			end--;
		}
		else
		{
			break;
		}
	}
	arr[end + 1] = tmp;
}

我们把end作为了已排数列的最后一个元素的位置,由此可知我们的整套排序,end从0到n-1:

void InsertSort(int arr[], int n)
{
	int i = 0;
	for (; i < n - 1; i++)
	{
		int end = i;
		int tmp = arr[end + 1];

		while (end >= 0)
		{
			if (arr[end] > tmp)
			{
				arr[end + 1] = arr[end];
				end--;
			}
			else
			{
				break;
			}
		}
		arr[end + 1] = tmp;

	}
}

3.4特点:

时间复杂度:

最坏情况:O(N^2) —— 逆序
最坏情况:O(N) —— 顺序有序

空间复杂度:

O(1)

稳定性:

稳定

什么是稳定性?

保证排序前相同的两个数的相对位置在排序后仍保持不变。 

四、希尔排序

4.1基本思路:

1.预排序:取间隔的数,为一组,对每一组进行插入排序
2.插入排序:对整体进行插入排序

4.2思路讲解:

4.3代码:

我们把插入排序的单趟间隔从1改为gap,完成希尔排序的第一步:

void ShellSort(int arr[], int n)
{
	int end = 0;
	int gap = 3;
	int tmp = arr[end + 1];

	while (end >= 0)
	{
		if (arr[end] > tmp)
		{
			arr[end + gap] = arr[end];
			end -= gap;
		}
		else
		{
			break;
		}
	}
	arr[end + gap] = tmp;
}

把以上操作重复gap次即为所求代码: 

void ShellSort(int arr[], int n)
{
	int gap = 3;
	for (int j = 0; j < gap; j++)
	{
		for (int i = j; i < n - gap; i += gap)
		{
			int end = i;
			int tmp = arr[end + 1];

			while (end >= 0)
			{
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

 我们可以对上述代码进行优化,让它变为gap组同时排序:

void ShellSort(int arr[], int n)
{
	int gap = 3;
	
	for (int i = 0; i < n - gap; i++)
	{
		int end = i;
		int tmp = arr[end + gap];

		while (end >= 0)
		{
			if (arr[end] > tmp)
			{
				arr[end + gap] = arr[end];
				end -= gap;
			}
			else
			{
				break;
			}
		}
		arr[end + gap] = tmp;
	}
}

我们这还只是完成了第一步,接下来我们要进行插入排序:

void ShellSort(int arr[], int n)
{
	int gap = 3;
	
	for (int i = 0; i < n - gap; i++)
	{
		int end = i;
		int tmp = arr[end + gap];

		while (end >= 0)
		{
			if (arr[end] > tmp)
			{
				arr[end + gap] = arr[end];
				end -= gap;
			}
			else
			{
				break;
			}
		}
		arr[end + gap] = tmp;
	}
	int i = 0;
	for (; i < n - 1; i++)
	{
		int end = i;
		int tmp = arr[end + 1];

		while (end >= 0)
		{
			if (arr[end] > tmp)
			{
				arr[end + 1] = arr[end];
				end--;
			}
			else
			{
				break;
			}
		}
		arr[end + 1] = tmp;
	}
}

学到这里,其实这些分布的并非是真正的希尔排序,gap到底取多少的值?真的要分成两步?其实希尔排序的gap是随时变换的,最后gap的值为1时,才正好进行最后的插入排序,但gap的取值官方也未说明何时最好,我们只需要保证最后一次排序gap的值刚好为1即可:

void ShellSort(int arr[], int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = arr[end + gap];

			while (end >= 0)
			{
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

4.4特点:

希尔排序的复杂度分析是个复杂的问题,它的计算还涉及到数学领域中尚未解决的难题,但有人指出当n在特定范围时,其复杂度接近O(n^1.3),当n->无穷大时,可以减少到O(n*(logn)^2)

时间复杂度:O(n^1.3)

空间复杂度:O(1)

稳定性:不稳定

五、选择排序

5.1基本思路:

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

5.2思路讲解:

选择排序其实没有什么难点,就是挨个比较然后将最小的换到首位,但其实我们可以同时找最大和最小值,然后让其找到对应的位置后再继续找次大的和次小的。

但是有一点需要注意,那就是当最后我们交换时,如果begin位置和maxi位置重合,那么先交换mini和begin的话,就无法找到正确的maxi值,反之同理,所以我们要多加一层判断来确保。

5.3代码:

首先我们先看一下我们需要新添加的变量:
1.标记交换最小值位置的begin和交换最大值位置的end,当一次选择完成后,他们标记的位置就会向后和向前挪动1个单位。
2.标记最大值最小值位置的maxi和mini,我们要记录当前最大值与最小值的元素下标,当每趟结束后与先前记录的begin和end交换。

void SelectSort(int arr[], int n)
{
	int begin = 0;
	int end = n - 1;
	
	while (begin < end)
	{
		int mini = begin;
		int maxi = begin;
		for (int i = begin; i <= end; i++)
		{
			if (arr[i] < arr[mini])
			{
				mini = i;
			}
			if (arr[i] > arr[maxi])
			{
				maxi = i;
			}
		}
		Swap(&arr[mini], &arr[begin]);
		if (maxi == begin)
		{
			maxi = mini;
		}
		Swap(&arr[maxi], &arr[end]);
		begin++;
		end--;
	}
}

5.4特点:

时间复杂度:

最好的情况:O(n^2)
最坏的情况:O(n^2)

空间复杂度:O(1)

稳定性:不稳定

六、堆排序

6.1基本思路:

利用大堆或小堆,每次找到一个最大值或最小值作为根结点并输出,再次进行堆排序,找到次大或次小值,重复上述操作。

6.2思路讲解:


6.3代码:

void AdjustUp(int* a, int child)
{
	while (child > 0)
	{
		int parent = (child - 1) / 2;
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
		}
		else
		{
			return;
		}
	}
}
void AdjustDown(int* a, int size, int parent)
{
	//假设左孩子小
	int child = parent * 2 + 1;
	while (child < size)
	{
		if (child + 1 < size && a[child] < a[child + 1])
		{
			child = child + 1;
		}
		if (a[parent] < a[child])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			return;
		}
	}
}
//升序
void HeapSort(int* a, int n)
{
	//建大堆
	for (int i = 1; i < n; i++)
	{
		AdjustUp(a, i);
	}
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}

6.4特点:

时间复杂度:O(N*logN)

空间复杂度:O(1)

稳定性:不稳定

七、快速排序(hoare版本)

7.1基本思路:

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

7.2思路讲解:

我们需要用两个指针,一个从前走,一个从后走,依次筛选满足条件的值,若不满足条件则交换。
还有一个小细节:我们要让右边指针先走,这样左右指针相遇时永远指向比key小的值,这样让left和key交换才能完成排序。

下面我们先来完成单趟,选用一个key值作为基准值,小的排在左边,大的排在右边,这样一次可以把整个数组分为两部分,然后我们还要进行基准值位置的调整,此时的left位置就是key应在的位置。

然后我们再分别对左右两边进行同样的步骤,即递归,当只剩下一个元素时就可以结束我们的递归操作,此时我们的数组也全部排序完成。

7.3代码:

首先我们来看新加变量,left和right指针,负责分别从两侧检索,keyi为此次所选的基准值的下标,但是需要注意的是,我们的left指针和keyi指针不能指向一个位置,我们的keyi指向的元素是不能和right指向的值进行交换的!

void QuickSort(int* a, int n)
{
	int right = n - 1;
	int keyi = 0;
	int left = keyi + 1;
	while (left < right)
	{
		//右边找小 
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		//左边找大
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[keyi], &a[left]);
}

完成了单趟排序以后,我们要进行递归调用,所以此时我们函数体引用不便再使用n作为区间标记,而是需要改用begin和end作为区间的分割点,使我们调用函数更加准确,然后递归调用的区间就是[begin,keyi-1] key [key+1,end]

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	int keyi = begin;
	int right = end;
	int left = begin;//left和begin位置需要一样 坑一
	while (left < right)
	{
		//右边找小 
		while (left < right && a[right] >= a[keyi])//前面条件 坑二 后面条件=号 坑三
		{
			right--;
		}
		//左边找大
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[keyi], &a[left]);
	keyi = left;
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi + 1, end);
}

7.4特点:

时间复杂度:O(N*logN)
空间复杂度:O(N)
稳定性:不稳定

八、快速排序(挖坑法和前后指针版本)

8.1挖坑法

8.1.1挖坑法讲解

这个方法我原称其为左右横跳方法。这个坑一直在左右横跳,当左右指针相遇时,把Key值填入即可。而且我们可以发现左右指针的规律,没有指向坑的指针走。


8.1.2代码:

我们先把QuickSort的代码改一改,让它能更方便的测试我们的三个方法:
 

//hoare版本
int PartSort1(int* a, int begin, int end)
{
	
	int keyi = begin;
	int right = end;
	int left = begin;
	while (left < right)
	{
		//右边找小 
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		//左边找大
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[keyi], &a[left]);
	return left;
}

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;

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

我们再来看挖坑法:我们使用数组额外的新变量key来直接控制基准值,我认为这比用数组的某个下标控制更加稳定,然后每次都把坑用key的值填上也是为了更加稳定的控制:

//挖坑法
int PartSort2(int* a, int begin, int end)
{
	int hole = begin;
	int key = a[begin];
	while (begin < end)
	{
		if (begin != hole)
		{
			while (begin < end && a[begin] <= key)
			{
				begin++;
			}
			a[end] = a[begin];
			a[begin] = key;
			hole = begin;
		}
		if (end != hole)
		{
			while (begin < end && a[end] >= key)
			{
				end--;
			}
			a[begin] = a[end];
			a[end] = key;
			hole = end;
		}
	}
	return hole;
}

 8.2前后指针版本

8.1.1前后指针讲解

其实画图把整个流程完整的走一遍我们就可以知道我们的目的是为了让prev和cur指针中间的值都是比key大的值,然后prev++负责记录下一个大的值,cur负责记录比key小的值,每次找到就交换,最后再把prev的值变为key即可。
如果看不懂,建议自己画一遍实操一下即可。

8.1.2代码: 

//前后指针版本
int PartSort3(int* a, int begin, int end)
{
	int key = a[begin];
	int prev = begin;
	int cur = begin + 1;
	while (cur <= end)
	{
		if (a[cur] < key)
		{
			prev++;
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[prev], &a[begin]);
	return prev;
}

 我们也可以在第一个大while循环中把if换成while:

int PartSort3(int* a, int begin, int end)
{
	int key = a[begin];
	int prev = begin;
	int cur = begin + 1;
	while (cur <= end)
	{
		while (cur <= end && a[cur] > key)
		{
			cur++;
		}
		if (cur <= end)
		{
			prev++;
			Swap(&a[prev], &a[cur]);
			cur++;
		}
	}
	Swap(&a[prev], &a[begin]);
	return prev;
}

九、归并排序 

9.1基本思路:

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;
即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

9.2思路讲解:

我们的归并排序是运用分治法的一个排序,下面是分的过程:

 我们看到了控制分停止的条件就是begin>=end,下面我们看合的过程:

每次合都会把合到一起的几个元素排序,因为我们是数组, 所以我们还需要一个新数组负责挪动数据。 

9.3代码:

根据思路讲解,我们先来看分的过程:

if (begin >= end)
		return;
	//分
	int mid = (begin + end) / 2;
	MergeSort(a, begin, mid, tmp);
	MergeSort(a, mid + 1, end, tmp);

然后我们只需要完成一次合的过程:

    //合
	int begin1 = begin;
	int end1 = mid;

	int begin2 = mid + 1;
	int end2 = end;
	
	int i = begin;
	while (begin1 <= end1 && begin2 <= end2 )
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}

最后把tmp复制到我们正式的数组上即可:

memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
void MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin >= end)
		return;
	//分
	int mid = (begin + end) / 2;
	MergeSort(a, begin, mid, tmp);
	MergeSort(a, mid + 1, end, tmp);
	
	//合
	int begin1 = begin;
	int end1 = mid;

	int begin2 = mid + 1;
	int end2 = end;
	
	int i = begin;
	while (begin1 <= end1 && begin2 <= end2 )
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}
	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}

9.4特点:

时间复杂度:O(N*logN)
每层的时间复杂度是O(N),因为二分,一共有logN层。
空间复杂度:O(N)
稳定性:

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

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

相关文章

openssl3.2 - 测试程序的学习 - test\acvp_test.c

文章目录 openssl3.2 - 测试程序的学习 - test\acvp_test.c概述笔记要单步学习的测试函数备注END openssl3.2 - 测试程序的学习 - test\acvp_test.c 概述 openssl3.2 - 测试程序的学习 将test*.c 收集起来后, 就不准备看makefile和make test的日志参考了. 按照收集的.c, 按照…

IPv6报文格式(全网最详细)

IPv6报文格式 报文格式 图1 IPv6报文头格式 表1 IP头字段解释 字段长度含义Version4比特 4&#xff1a;表示为IPV4&#xff1b;6&#xff1a;表示为IPV6。Traffic class8比特流量类别。该字段及其功能类似于IPv4的业务类型字段。该字段以区分业务编码点&#xff08;DSCP&…

C语言——操作符详解2

目录 0.过渡0.1 不创建临时变量&#xff0c;交换两数0.2 求整数转成二进制后1的总数 1.单目表达式2. 逗号表达式3. 下标访问[ ]、函数调用( )3.1 下标访问[ ]3.2 函数调用( ) 4. 结构体成员访问操作符4.1 结构体4.1.1 结构体的申明4.1.2 结构体变量的定义和初始化 4.2 结构体成…

房产信息网源码,房产系统,二手房小程序源码,租房小程序系统楼盘系统房产经纪人系统

房产门户系统、多城市房产网、房产小程序 房产网系统、地方房产门户信息网 带im即时通讯聊天 二手房 租房 楼盘 置业顾问 经纪人 腾房云房产网 分为单城市版本 和多城市版本 多城市 自动定位当前城市 每个分站对应独立管理员分站管理 thinkphpuniapp 独立开源

【开源】基于JAVA语言的二手车交易系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手车档案管理模块2.3 车辆预约管理模块2.4 车辆预定管理模块2.5 车辆留言板管理模块2.6 车辆资讯管理模块 三、系统设计3.1 E-R图设计3.2 可行性分析3.2.1 技术可行性分析3.2.2 操作可行性3.2.3 经济…

02-opencv-上

机器视觉概述 机器视觉是人工智能正在快速发展的一个分支。简单说来&#xff0c;机器视觉就是用机器代替人眼来做测量和判断。机器视觉系统是通过机器视觉产品(即图像摄取装置&#xff0c;分CMOS和CCD两种)将被摄取目标转换成图像信号&#xff0c;传送给专用的图像处理系统&…

[Python图像处理] 使用OpenCV创建深度图

使用OpenCV创建深度图 双目视觉创建深度图相关链接双目视觉 在传统的立体视觉中,两个摄像机彼此水平移动,用于获得场景上的两个不同视图(作为立体图像),就像人类的双目视觉系统: 通过比较这两个图像,可以以视差的形式获得相对深度信息,该视差编码对应图像点的水平坐标的…

C++ 内存占用分析(内存泄漏)

文章目录 前言一、什么是内存泄漏二、如何检测内存泄漏1、内存占用变化排查法2、valgrind定位法3、mtrace定位法 参考资料 前言 内存占用分析是一个比较庞大的话题&#xff0c;在C程序中&#xff0c;进程的内存持续上涨&#xff0c;有可能是正常的内存占用&#xff0c;有可能是…

Linux之安装配置CentOS 7

一、CentOS简介 CentOS&#xff08;Community Enterprise Operating System&#xff0c;中文意思是社区企业操作系统&#xff09;是Linux发行版之一&#xff0c;它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码&#xff0c…

1、PDManer 快速入门

文章目录 序言一、快速入门1.1 PDMan 介绍1.2 特点1.3 下载和安装 小结 序言 本人长期以来一直从事于应用软件的研发以及项目实施工作&#xff0c;经常做数据库建模&#xff08;数据表设计&#xff09;。有一款称心如意的数据库建模工具&#xff0c;自然能够事半功倍&#xff0…

uniapp 实现路由拦截,权限或者登录控制

背景&#xff1a; 项目需要判断token&#xff0c;即是否登录&#xff0c;登录之后权限 参考uni-app官方&#xff1a; 为了兼容其他端的跳转权限控制&#xff0c;uni-app并没有用vue router路由&#xff0c;而是内部实现一个类似此功能的钩子&#xff1a;拦截器&#xff0c;由…

「研发部」GitFlow规范-升级版(二)

前言 上一篇文章简单整理过一次产研团队的GitFlow《Git 分支管理及Code Review 流程 (一)》 GitFlow是一种流行的Git分支管理策略&#xff0c;它提供了一种结构化的方式来管理项目的开发和发布流程。以下是GitFlow规范的主要组成部分&#xff1a; 主要分支&#xff1a; mast…

[Tomcat] [从安装到关闭] MAC部署方式

安装Tomcat 官网下载&#xff1a;Apache Tomcat - Apache Tomcat 9 Software Downloads 配置Tomcat 1、输入cd空格&#xff0c;打开Tomca目录&#xff0c;把bin文件夹直接拖拉到终端 2、授权bin目录下的所有操作&#xff1a;终端输入[sudo chmod 755 *.sh]&#xff0c;回车 …

Authorization Failed You can close this page and return to the IDE

一.问题描述 注册JetBrains成功&#xff0c;并且通过了学生认证&#xff0c;但在activate pycharm时&#xff0c;却显示Authorization Failed You can close this page and return to the IDE如上图 二.原因&#xff1a; 可能是因为之前使用了破解版pycharm 三.解决方法&am…

第17节-高质量简历写作求职通关-投递反馈

&#xff08;点击即可收听&#xff09; 投递跟进和感谢信 如果对一家公司特别心仪&#xff0c;但是投递简历后一直得不到回复怎么办&#xff1f; 面试之后觉得自己没有表现好怎么办&#xff1f; 面试完几天了&#xff0c;依然没有得到回应怎么办&#xff1f; 这个时候你需要写一…

Asp.Net Core Webapi 配置全局路由 及 示例代码 下载

在开发项目的过程中&#xff0c;我新创建了一个controller&#xff0c;发现vs会给我们直接在controller头添加前缀&#xff0c;比如[Route("api/[controller]")],即在访问接口的时候会变成http://localhost:8000/api/values&#xff0c;但是如果控制器有很多个&#…

C++类和对象——深拷贝与浅拷贝详解

目录 1.深拷贝和浅拷贝是什么 2.案例分析 完整代码 1.深拷贝和浅拷贝是什么 看不懂没关系&#xff0c;下面有案例分析 2.案例分析 浅拷贝可能会导致堆区的内存重复释放 一个名为person的类里面有年龄和指向身高的指针这两个成员。 当我们执行到person p2&#xff08;p1&am…

仿写ls -li 获取某一个路径下的所有文件的文件属性(不用管文件创建者和属组,也不要隐藏文件)

1》stat&#xff1a; 查看一个文件的属性 #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int stat(const char *pathname, struct stat *statbuf); 形参&#xff1a;pathname 文件名 statbuf&#xff1a;获取到的文件属性存放的…

四、vtk相机类vtkCamera的使用

在三维渲染场景中,相机好比观众的眼睛,人站立的位置影响事物的大小,视角的不同影响看到事物的范围,目光的朝向影响看到事物的正反。 vtkCamera负责把三维场景投影到二维平面,如屏幕、图像等。 下图为相机投影示意图: 相机位置:即相机所在的位置,用方法vtkCamera::Se…

C/C++ - 类的封装特性

目录 类的封装 语法格式 声明定义 分文件 访问权限 类作用域 对象模型 构造函数 默认构造函数 带参构造函数 拷贝构造函数 构造函数重载 委托构造函数 初始数据列表 构造默认参数 构造函数删除 析构函数 析构函数概念 析构函数特性 析构函数示例 析构调用…