数据结构初阶之排序

个人主页:点我进入主页

专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶

C语言刷题       数据结构初阶    Linux

欢迎大家点赞,评论,收藏。

一起努力,共赴大厂。

目录

一.前言

二.选择排序

2.1选择排序思想

2.2代码实现

三.快速排序

3.1霍尔的思想

3.2代码实现

3.3代码性能分析与改进

 3.3.1优化点一

3.3.2优化点二

3.4挖坑法

 3.5代码实现

3.6双指针法

3.7代码实现

3.8非递归实现快速排序

四.归并排序

4.1归并的思想

4.2代码实现 

4.3非递归思想 

4.4代码实现

五.计数排序 

 5.1计数排序思想

5.2代码实现

六.总结


一.前言

        在前面我们写过冒泡排序,堆排序,插入排序以及希尔排序。今天我主要给大家带来的包括选择排序,快速排序的霍尔版本。其中选择排序就是找到最大最小的数然后放在两边然后进行循环,进行下一次的最大最小数据的查找替换,其中有一个坑,坑在哪里后面会说,对于霍尔的快速排序,既然叫快速排序,那么它必然会非常的快,这个需要我们找到一个关键值然后进行,由于霍尔版本的坑非常的多,又有一些大佬对霍尔的快速排序进行了修改,包括思路类似的挖坑法和另一种思路不同的双指针法,这些内容逐渐的进行讲解。

二.选择排序

2.1选择排序思想

        选择排序我们先排第一趟,我们先找到最大和最小的数,例如我们想要将数组形成升序,我们将小的放在前面,大的放在后面,这就形成了我们的第一趟,我们将前和后进行调整,然后重复这样的过程,就会形成我们的选择排序,我们可以看一下动图,可以更好的了解我们的选择排序。

2.2代码实现

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

我们运行我们的程序我们可以看到

看到这里我们可以看到我们的程序出现了问题,没有达到我们的预期,那么问题出现在那里了?我们进行调试

我们可以看到这时候我们的mini的值为9,maxi的值为0,我们先进行交换我们可以看到数组的元素变成了0,8,7,6,5,4,3,2,1,9.我们的maxi的值为0,但是我们的最大值却在9的位置,所以我们需要在第一个数据交换的位置加一个判断条件,

		if (maxi == begin)
		{
			maxi = mini;
		}

我们运行代码后我们运行后我们可以看到

我们的全部代码为

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

三.快速排序

3.1霍尔的思想

        对于霍尔的快速排序,我们就是根据递归进行写的,先找出一个关键值,我们想要一个升序的序列,我们将这个关键值得左边全部小于它,右边全部大于它,然后进行递归,我们同样进行第一次排序,我们先找在右边开始小于这个关键值得数,然后在左边开始,找到大于这个关键值的数只要这两个不相交,进行这两个数进行交换,相遇的时候我们将这个关键值和相遇的位置进行交换,这就是我们的第一趟排序,然后进行递归。在这里我们有很多坑,也有一个问题,为什么保证最后的值为最小的,这个问题我们后面会进行讲解。接下来我们看一组动图,来深刻了解一下霍尔的排序思路

3.2代码实现

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;
	int keyi = begin;
	int left = begin, right = end;
	while (left < right)
	{
		while (left < right && a[right] <= a[keyi])
		{
			right--;
		}
		while (left < right && a[left] >= a[keyi])
		{
			left++;
		}
		Swap(&a[right], &a[left]);
	}
	Swap(&a[left], &a[keyi]);
	keyi = left;
	QuickSort(a, begin, keyi-1);
	QuickSort(a, keyi + 1, end);
}

在这个代码里面有几个坑,第一个是在while循环里面的while循环的判断条件需要加上left<right否则容易造成数组越界访问,第二个就是个在进行数据交换时容易将keyi和数据进行交换。针对这几个有人写出了较为容易的快速排序。在这里我们的问题来了?如何保证最后和a[keyi]交换的数是小于a[keyi]的,我们知道left和right相遇有两种结果,第一种,left遇到right,这时候说明right已经找到了小于的数,这时候相遇就是小于,第二种right遇到left,右边遇到左边说明左边已经是交换了的小于的数,这时候相遇也是小于的数。

3.3代码性能分析与改进

 3.3.1优化点一

        我们做一个随机数产生的数组,我们的代码如下:

int main()
{
	srand(time(0));
	int n = 100000;
	int* a1 = (int*)malloc(sizeof(int) * n);
	int* a2 = (int*)malloc(sizeof(int) * n);
	int* a3 = (int*)malloc(sizeof(int) * n);
	int* a4 = (int*)malloc(sizeof(int) * n);
	int* a5 = (int*)malloc(sizeof(int) * n);
	int* a6 = (int*)malloc(sizeof(int) * n);
	int* a7 = (int*)malloc(sizeof(int) * n);
	for(int i = 0; i < n; i++)
	{
		a1[i] = i + rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
		a7[i] = a1[i];
	}

	int begin1 = clock();
	ShellSort(a1, n);
	int end1 = clock();
	printf("ShellSort:%d\n", end1 - begin1);

	int begin2 = clock();
	QuickSort(a1, 0,n-1);
	int end2 = clock();
	printf("QuickSort:%d\n", end2 - begin2);
	return 0;
}

这个代码用于计算函数使用的毫秒数,我们在release版本进行实验,由于我们的数据量是十万,由于随机数产生的数据为3万多,我们在数据后还加了一个i这样我们就会将数据看成近似于有序,我们运行代码可以看到 

我们知道希尔排序和快速排序时间复杂度都是nlogn但是为什么会相差这么多呢?这主要就是数组类似有序造成的后果,这时候我们可以做一些优化,我们去取区间中的开头数据,结尾数据,中间数据中不大不小的数据,然后让他和开头进行交换,我们让它做为我们的关键值,取中代码如下:

int GetMid(int* a, int begin, int end)
{
	int mid = (begin + end) / 2;
	if (a[mid] > a[begin])
	{
		if (a[end] > a[mid])
		{
			return mid;
		}
		else if (a[end] < a[begin])
		{
			return begin;
		}
		else
		{
			return end;
		}
	}
	else
	{
		if (a[mid] > a[end])
		{
			return mid;
		}
		else if (a[end] > a[begin])
		{
			return begin;
		}
		else
		{
			return end;
		}

	}
}

这样我们运行我们的代码可以看到

我们的快排变快了很多。

3.3.2优化点二

        我们知道快速排序是递归大方式进行的,我们可以化成图为

我们的最后一层占用的递归次数将近占总体的50%,我们的倒数第二次大约占25%,倒数第三次大约占12.5%,仅仅是这三次就将近占总体递归的87.5%,我们知道debug版本和release版本中我们用debug版本,递归占用的内存还是很多的,但是release版本下编译器已经做了优化,让递归变得好很多,我们的优化点二主要针对于debug版本进行的, 我们将最后的区间中在10个左右时我们用插入排序进行,为什么什么使用插入排序呢?这个主要原因就是我们使用希尔排序的话就有点过了,使用堆排序的话我们还需要进行建堆,比较麻烦,所以这时候我们的插入排序就非常good了,我们的进一步修改为:

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

	int midi = GetMid(a, begin, end);
	Swap(&a[midi], &a[begin]);

	if (end - begin + 1 <= 10)
	{
		InsertSort(a + begin, end - begin + 1);
	}
	else
	{
		int keyi = QuickSort1(a, begin, end);
		QuickSort(a, begin, keyi - 1);
		QuickSort(a, keyi + 1, end);
	}
}

 

我们可以看到我们的调整后有时候大有时候小,有时候相等,在release版本下

我们调整数据的长度,可以看到大部分情况下调整还是会变慢。

3.4挖坑法

        挖坑法的主要原理就是出现一个hole进行数据的交换,这样每一趟的结果虽然不同但是最后的结果相同,我们看一看动图来了解一下挖坑法

 3.5代码实现

int QuickSort2(int* a, int begin, int end)
{
	int key = a[begin], hole = begin;
	int left = begin, right = end;
	while (left < right)
	{
		while (left < right && a[right] >= key)
		{
			right--;
		}
		Swap(&a[right], &a[hole]);
		hole = right;
		while (left < right && a[left] <= key)
		{
			left++;
		}
		Swap(&a[left], &a[hole]);
		hole = left;
	}
	a[hole] = key;
	return hole;
}

 挖坑法就是先把key保存来,然后我们把起始位置定义为我们的洞,然后先找右边,然后进行填坑,然后新坑就是我们交换过去的数的原始位置,然后再从左边开始,一样进行填坑,挖坑,最后将坑的位置填上key。这样我们的一层排序就完成了,我们在进行递归就完成了。

3.6双指针法

        双指针法是一种非常简单的方式,其核心思想就是我们想要升序,南无prev和cur之间的就是大于key的值,然后进行数据交换,让大的数跳到后边去,小的数跳到前边,我们的动图为

3.7代码实现

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

        这个代码非常巧妙,我们的cur无论任何情况都会++,只有a[cur]小于key时才交换,当然prev++后和cur相等的时的交换是无意义的所以,可以舍去。

3.8非递归实现快速排序

        针对我们的非递归实现我们的快速排序,我们可以选择用栈去进行模拟实现,栈的作用就是帮助我们去存储我们的开始和结尾的下标,我们可以利用栈空来判断循环,我们的代码如下:

void QuickSortNonP(int* a, int begin, int end)
{
	Stack s;
	InitStack(&s);
	PushStack(&s, begin);
	PushStack(&s, end);
	while (!EmptyStack(&s))
	{
		end = TopStack(&s);
		PopStack(&s);
		begin = TopStack(&s);
		PopStack(&s);

		int midi = GetMid(a, begin, end);
		Swap(&a[midi], &a[begin]);

		int keyi = QuickSort3(a, begin, end);

		if(keyi-1>begin)
		{
			PushStack(&s, begin);
			PushStack(&s, keyi - 1);
		}
		if(end>keyi+1)
		{
			PushStack(&s, keyi + 1);
			PushStack(&s, end);
		}
	}
    DestoryStack(&s);
}

在这里我们先将原有数组的开始和结尾的下标进行存储,然后进入循环,我们出栈得到我们的开始和结尾的下标,三数取中,我们利用双指针法找到我们的keyi,然后当区间中的元素数量大于1时我们入栈进行存储下标,这样进行循环就可以模拟非递归进行快速排序。

四.归并排序

4.1归并的思想

        在归并排序中我们有递归的方式和非递归的方式,递归中们需要对数据进行分组,我们进行递归将数据变成每组有序,这时候我们进入我们的合并环节,我们每相邻的两组有序数组进行合并,合成新的有序数组,我们可以将这个步骤画成

我们可以将这个过程看成我们的二叉树的后序遍历的过程,我们进行数组合并时我们做的相当于两个有序数组合并成一个有序数组,这样我们进行合并就可以完成。我们看一看动图,就可以更好的了解一下这个过程,

 

4.2代码实现 

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 i = begin, j = mid + 1;
	int k = i;
	while (i <= mid && j <= end)
	{
		if (a[i] < a[j])
		{
			tmp[k++] = a[i++];
		}
		else
		{
			tmp[k++] = a[j++];
		}
	}
	while (i <= mid)
	{
		tmp[k++] = a[i++];
	}
	while (j <= end)
	{
		tmp[k++] = a[j++];
	}
	memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}
void MergeSort(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	_MergeSort(a, 0, n - 1, tmp);
	memcpy(a, tmp, sizeof(int) * n);
}

4.3非递归思想 

        对于非递归的方式,我们想到是否可以使用栈来实现呢?类似于快速排序的非递归一样,但是我们在取栈顶元素时我们的栈的元素就会取出来,我们分成单个以后就不能干任何事情了,所以这种方式是不可以的,那我们应该如何去做呢?这时候需要我们对归并排序的递归形式的运行过程有深刻的了解,我们可以去模拟递归的过程去完成非递归,我们可以使用一个gap,当gap为1时我们的每一组的数组的长度都是1,这时我们相邻的两组之间进行有序数组合并,我们用四个变量来保存数组的范围,我们利用i来实现组的变换,这时候我们会遇到范围的越界,这时候我们需要一些判断,由于i小于n所以第一个数不需要判断,当第二个数大于等于n时我们就没有了第二组,这时候由于数组有序,所以不需要排序,当第三个数大于等于时也是不需要排序,第四个数大于等于时我们直接对他进行赋值即可。

4.4代码实现

void _MergeSortNonP(int* a, int n, int* tmp)
{
	int gap = 1;
	while(gap<n)
	{
		for (int i = 0; i < n; i = i + 2 * gap)
		{
			int begin1 = i, end1 = begin1 + gap - 1;
			int begin2 = begin1 + gap, end2 = begin2 + gap - 1;
			int j = i;
			if (end1 >= n || begin2 >= n)
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tmp[j++] = a[begin1++];
				}
				else
				{
					tmp[j++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tmp[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tmp[j++] = a[begin2++];
			}
			memcpy(a + i, tmp + i, (end2 - i + 1) * sizeof(4));
		}
		gap *= 2;
	}
}
void MergeSortNonP(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc fail");
		return;
	}
	_MergeSortNonP(a, n, tmp);
}

五.计数排序 

 5.1计数排序思想

        对于计数排序,我们用到了哈希表和相对映射,我们先找到最大最小值,然后开辟最大-最小+1大小的数组,然后进行计数,计数的位置为a[i]-min,然后我们映射回去就可以得到排序后的数组,计数排序的时间复杂度为o(n),但是它有一些局限,最大和最小相差很多时我们使用这个会非常麻烦。

5.2代码实现

void CountSort(int* a, int n)
{
	int max=0, min=0;
	for (int i = 0; i < n; i++)
	{
		if (a[i] > max)
		{
			max = a[i];
		}
		if (a[i] < min)
		{
			min = a[i];
		}
	}
	int* hash = (int*)calloc(max - min+1, sizeof(int));
	memset(hash, 0, sizeof(int) * (max - min + 1));
	for (int i = 0; i < n; i++)
	{
		hash[a[i] - min]++;
	}
	int j = 0;
	for (int i = 0; i < max - min + 1; i++)
	{
		while (hash[i]--)
		{
			a[j++] = i;
		}
	}
}

六.总结

        我们知道排序分为内存排序和外排序,我们写过的八种排序都是内排序,内排序就是在内存中进行排序,我们知道内存就是量小,价格贵,带电存储的,我们的外排序就是储存在硬盘中,其中我们的归并排序也是外排序,例如我们想要排序存在文件中的数据,这时候我们需要我们的归并排序了,归并排序是对于有序的数组进行归并,我们可以选取一些数据使用快速排序,希尔排序等较快的排序,然后让他们变成有序的数组,然后使用归并排序,这里不做具体的写法,只提供一个思路。最后希望大家可以一件三连,点点赞支持一下。

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

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

相关文章

智能安全帽识别系统简析

在工业安全领域&#xff0c;安全帽识别系统的重要性不言而喻。这种系统利用先进的图像识别技术&#xff0c;确保工地上每位工人都佩戴安全帽&#xff0c;从而大幅提升工作场所的安全性。本文旨在探讨这一系统的工作原理、应用范围以及面临的挑战。 安全帽识别系统的工作原理 智…

GPT图解大模型是怎样构建的

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

0基础学java-day25(JDBC 和数据库连接池)

一、JDBC概述 1 基本介绍 2 简单模拟 package com.hspedu.jdbc.myjdbc;/*** author 林然* version 1.0* 我们规定的 jdbc 接口(方法)*/ public interface JdbcInterface {//连接public Object getConnection() ;//crudpublic void crud();//关闭连接public void close(); }pac…

立白科技集团:研发安全推动数字化蜕变,日化业务再上新高度

立白科技集团成立于1994年&#xff0c;是我国日化行业的领军企业&#xff0c;致力于成为一家“品牌引领、数字经营、富有创新、富有活力”的智慧服务型企业。从2018年开始&#xff0c;立白科技集团加速数字化转型&#xff0c;打造数据和业务中台&#xff0c;并建立toB和toC平台…

小程序学习基础(首页展示)

原理通过首页展示的方式设置一个按钮&#xff0c;然后点击按钮跳转到相应的页面即可。 一 在js中定义一个需要展示页面的数组 二 在页面中使用fou循环来遍历其中的数据&#xff0c;并展示出来 页面代码 <!--index.wxml--> <navigation-bar title"牧原" …

vue3 锚点定位 点击滚动高亮

功能描述 点击导航跳到对应模块的起始位置&#xff0c;并且高亮点击的导航&#xff1b; 滚动到相应的模块时&#xff0c;对应的导航也自动高亮&#xff1b; 效果展示 注意事项 一定要明确哪个是要滚动的盒子&#xff1b;滚动的高度要减去导航栏的高度&#xff1b;当前在导航1…

Redis相关命令详解及其原理

Redis概念 Redis&#xff0c;英文全称是remote dictionary service&#xff0c;也就是远程字典服务。这是kv存储数据库。Redis&#xff0c;包括所有的数据库&#xff0c;都是请求-回应模式&#xff0c;通俗来说就是数据库不会主动地要给前台推送数据&#xff0c;只有前台发送了…

【HarmonyOS4.0】第十篇-ArkUI布局容器组件(二)

三、层叠布局容器&#xff08;Stack&#xff09; 堆叠容器组件 Stack的布局方式是把子组件按照设置的对齐方式顺序依次堆叠&#xff0c;后一个子组件覆盖在前一个子组件上边。 注意&#xff1a;Stack 组件层叠式布局&#xff0c;尺寸较小的布局会有被遮挡的风险&#xff0c; …

JS常用插件 Swiper插件 实现轮播图

Swiper介绍 Swiper 是一款免费以及轻量级的移动设备触控滑块的js框架 中文官网地址: https://www.swiper.com.cn/ 点击查看Swiper演示&#xff0c;里面的功能和样式十分丰富&#xff0c;根据自己的需求选择 中文教程中详细介绍了如何使用Swiper API文档中介绍了各个模块以及参…

计算机导论05-计算机网络

文章目录 计算机网络基础计算机网络概述计算机网络的概念计算机网络的功能计算机网络的组成 计算机网络的发展计算机网络的类型 网络体系结构网络互联模型OSI/RM结构与功能TCP/IP结构模型TCP/IP与OSI/RM的比较 网络地址与分配IP地址构成子网的划分IPv6 传输介质与网络设备网络传…

电脑桌面便签在哪设置?备忘录软件哪个好?

好记性不如烂笔头&#xff01;相信很多打工族在电脑面前办公的时候&#xff0c;都需要随时记录工作中的事项&#xff0c;有的用TXT记录&#xff0c;有的手写笔记&#xff0c;还有一些用电脑桌面便签类软件。而当我们待办事项繁多的时候&#xff0c;手写或文本记录并不能有效帮我…

图解python | 字符串及操作

1.Python元组 Python的元组与列表类似&#xff0c;不同之处在于元组的元素不能修改。 元组使用小括号&#xff0c;列表使用方括号。 元组创建很简单&#xff0c;只需要在括号中添加元素&#xff0c;并使用逗号隔开即可。 tup1 (ByteDance, ShowMeAI, 1997, 2022) tup2 (1…

老师假期有工资么

老师在享受假期的时候&#xff0c;很多人都会好奇&#xff1a;教师寒暑假会有工资吗&#xff1f; 老师也是劳动者&#xff0c;享有法律规定的各种权益。其中之一就是在规定的工作时间内获得报酬。既然老师在正常工作日上班有工资&#xff0c;那么在假期呢&#xff1f; 实际上…

数字化时代,VR全景展示如何让用户一窥全貌?

数字化时代&#xff0c;VR全景展示为各行各业提供了无限的可能性。随着VR全景技术的逐步普及&#xff0c;VR全景展示以其独特的呈现方式和新颖十足的交互体验&#xff0c;正在不断改变着人们对于展示宣传的理解。 传统的展示方式&#xff0c;通常需要将产品、图文、品牌等元素集…

【计算机组成与体系结构Ⅱ】指令调度与分支延迟(实验)

实验4&#xff1a;指令调度与分支延迟 一、实验目的 1. 加深对指令调度技术的理解。 2. 加深对分支延迟技术的理解。 3. 熟练采用指令调度技术解决流水线中的数据冲突的方法。 4. 进一步理解指令调度技术对CPU性能的改进。 5. 进一步理解延迟分支技术对CPU性能的改进。 二…

企业组网搭建有哪些?

在当今全球化的商业环境中&#xff0c;集团公司必须建立起一个无缝连接的网络&#xff0c;以确保高效的信息传输和资源共享。为实现这一目标&#xff0c;选择可靠而安全的网络组网方案至关重要。本文将介绍几种主要的集团公司网络组网方案&#xff0c;以帮助企业根据其具体需求…

人人都在用的PDF软件,也要接入ChatGPT了

随着人工智能技术的不断进步和发展&#xff0c;Chatbot技术的应用已经逐渐从娱乐和社交领域扩展到了更多的实际场景中。在办公软件领域&#xff0c;聊天机器人已经成为了提升工作效率、减少人力投入的重要工具&#xff0c;多家头部企业都在探讨将AI接入到软件及应用中的使用方案…

深入解析阻塞队列BlockingQueue及源码(超详细)

一、基础概念 1.1 BlockingQueue BlockingQueue 是 java.util.concurrent 包提供的用于解决并发生产者 - 消费者问题的最有用的类。 1.1.1 队列类型&#xff1a; 无限队列 &#xff08;unbounded queue &#xff09; - 几乎可以无限增长 有限队列 &#xff08; bounded qu…

python基础语法看一篇就够了,全网最全python语法笔记汇总

前言 Python 是一种代表简单思想的语言&#xff0c;其语法相对简单&#xff0c;很容易上手。不过&#xff0c;如果就此小视 Python 语法的精妙和深邃&#xff0c;那就大错特错了。 如能在实战中融会贯通、灵活使用&#xff0c;必将使代码更为精炼、高效&#xff0c;同时也会极…

Plane Geometry (Junior High School)

初中平面几何&#xff0c; ACBD, ∠CAD60&#xff0c;∠C40&#xff0c;求∠B Vertical Calculation-CSDN博客 Rectangular Area-CSDN博客