排序算法:插入、希尔、选择、推排、冒泡、快速、归并排序

news2024/11/26 23:46:12

排序算法

目录

前言

一、排序的概念

1.1排序的概念

1.2 常见的排序算法

二、常见排序算法的实现

2.1 插入排序

2.2 希尔排序

2.3 选择排序

2.4 堆排序

2.5 冒泡排序

2.6 快速排序

2.6.1 hoare版本

2.6.2 前后指针版本

2.6.3 非递归版本

2.7 归并排序

归并排序

2.8 计数排序

三、算法性能

总结


前言

今天为我们来通过C语言来实现常见排序算法:直接插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、堆排序,了解算法的具体实现和算法的性能。


一、排序的概念

1.1排序的概念

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次
序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排
序算法是稳定的;否则称为不稳定的。
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

1.2 常见的排序算法

二、常见排序算法的实现

2.1 插入排序

思想:把第一个元素当成有序,然后把下一个元素插入到这个有序序列里,使得保持有序,重复步骤我们可以n-1个元素排成有序,把第n个元素插入到有序序列里。
步骤:1.先把第一个元素当成有序
           2.取有序元素的最后下标end的下一个元素temp
           3.将temp从最后一个往前比较(end--),比temp大则元素往后移动,小则插入到end的后面。
           4.重复步骤2,3 循环n-1(n为数组长度)次
             

动画图解如下:

//插入排序
void InsertSort(int* a, int n)
{
	for (int i = 0; i < n - 1; i++) 
	{
		int end=i;
		int temp = a[end + 1];
		while (end >= 0)
		{
            //比较与end位置元素大小
			if (temp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
            //大于end位置元素,跳出
			else
			{
				break;
			}
		}
        //1.end大于零,temp放在end元素后一个
        //2.end小于零,temp也是放在end元素后,只不过此时为第一个元素
		a[end + 1] = temp;
	}
}

直接插入排序
时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定
最坏情况:逆序
最好情况是多少:顺序有序或者接近有序  O(N)

2.2 希尔排序

思想:插入排序最好的情况是有序,我们可以在插入排序之前进行预排序,使得序列变得接近有序

,先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序,重复上述步骤。然后排序就变得简单了。

步骤:1.我们定义一个gap为每组元素的之间的距离。
           2.把每个元素距离为gap的分为一组,进行插入排序
           3.gap减小(通常除2),再进行步骤2
           4.最后为gap减小到1,即每个元素各自为一组,即为插入排序
动画图解如下:
             
//希尔排序
void ShellSort(int* a, int n) {

	int gap=n;
	while (gap > 1) 
	{
		gap/=2;
        //循环到n-gap-1元素
		for (int i = 0; i < n-gap; i++)
		{
			int end = i;
			int temp = a[end + gap];
			while (end >= 0)
			{
				if (temp < a[end])
				{
					a[end + gap] = a[end];
					//end移动距离为gap
                    end -= gap;
				}
				else
				{
					break;
				}
			}
            //各自插入到每组元素
			a[end + gap] = temp;
		}
	}

}
1. 希尔排序是对 直接插入排序的优化
2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当 gap == 1 时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定
希尔排序

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

空间复杂度:O(1)

稳定性:不稳定

2.3 选择排序

思路:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。同时我们还可以更加精简算法,再选出最小的同时选出最大的,把最小的放在最左边,最大的放在最右边。
步骤:1.从头到尾遍历序列找出最大最小的值
           2.把最大最小值放在序列的尾和头
           3.序列向中间收,头加1,尾减1,重复1,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 + 1; i <= end; i++)
		{
			if (a[i] < a[mini])
			{
				mini = i;
			}
			if (a[i] > a[maxi])
			{
				maxi = i;
			}
		}
		Swap(&a[begin], &a[mini]);
		//避免二次交换
        if (begin == maxi)
			maxi = mini;
		Swap(&a[end], &a[maxi]);
		
        //缩小范围
		begin++;
		end--;

	}

}
直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
直接选择排序
时间复杂度: O(N^2)
空间复杂度: O(1)
稳定性:不稳定

2.4 堆排序

思路: 堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过 来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。
步骤:1.通过向下调整建堆( 排升序要建大堆,排降序建小堆)
           2.交换第一个和最后一个元素
           3.从零向下调整
           4.从堆的长度减一,开始重复步骤2,3
图解:
//堆排序
//向下调整
void AdjustDown(int* a, int n, int parent) {
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}

		if (a[child] > a[parent])
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}

	}
}
void HeapSort(int* a, int n) {
	
	//建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}


}
堆排序使用堆来选数,效率就高了很多。
堆排序
时间复杂度: O(N*logN)
空间复杂度: O(1)
稳定性:不稳定

2.5 冒泡排序

思路:从头开始依次遍历整个序列,如果遇到大的就交换,最后我们就把大的交换到最后了。
步骤:1.遍历序列(遍历n-1次)
           2.与下一个进行比较,比后一个大的就交换。
动画图解如下:
//冒泡排序
void BubbleSort(int* a, int n) {
	for (int i = 0; i < n - 1; i++)
	{
		int exchang = 0;
		for (int j = 1; j < n - i; j++)
		{
            //前一个比后一个大就交换
			if (a[j] < a[j - 1])
			{
				Swap(&a[j], &a[j - 1]);
				exchang = 1;
			}
		}
		if (exchang == 0)
			break;
	}
}

冒泡排序

时间复杂度: O(N^2)
空间复杂度: O(1)
稳定性:稳定

2.6 快速排序

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

选择基准值有多种方法:

1.直接选择头或者尾为基准值(但是序列为有序或者接近有序时间复杂度大)

2.随机数取基准值

//随机取基准值
int randi = rand() % (right - left + 1);
randi += left;
Swap(&a[left], &a[randi]);//基准值放到序列头

3.三位数取中

取序列头尾和中间三个数,让不是最大的,也不是最小的作为基准值。

//三位数取中
int midi = GetMidi(a, left, right);//取中间值函数
Swap(&a[midi], &a[left]);//基准值放到序列头

将区间按照基准值划分为左右两半部分的常见方式有:

2.6.1 hoare版本

思路:选择key(基准值),从尾向头开始找比key小的,然后再从头找比key大的,交换两者,然后继续整个步骤,直到它们两个相遇,交换key位置到相遇位置处,这样key前面就全为比key小的,后面全为比key大的,此时key为正确位置,然后分割序列,分为key前面的和key后面,重复上面所有步骤。

我们这直接选择最左边为key

步骤:1.最左边为key,定义left,right代表key下一个位置,序列尾

           2.让right向前走,找到比key小的,找到了停止

           3.让left向后走,找到比key大的,找到了停止

           4.交换此时righ和left的位置上的元素,重复2,3步骤

           5.直到相遇,交换此时相遇位置和key的。

           6.分割序列,分为keyi前面的序列和keyi后面的位置,重复以上所有步骤。

动画图解如下:

//快速排序 hoare版本
void QuickSort1(int* a, int left, int right) {
	//当只有一个元素和为空序列返回空
    if (left >= right)
		return;

	int begin = left, end = right;

    //取序列开头为key
	int keyi = left;
	
	while (left < right)
   	{    
        //找比key小的
		while (left < right && a[keyi] <= a[right])
		{
			right--;
		}
        //找比key大的
		while (left < right && a[keyi] >= a[left])
		{
			left++;
		}
        
		Swap(&a[left], &a[right]);
	}

	Swap(&a[left], &a[keyi]);
	keyi = left;

    //递归[begin,keyi-1] 和 [keyi+1,end]
	QuickSort1(a, begin, keyi - 1);
	QuickSort1(a, keyi+1, end);

}

2.6.2 前后指针版本

思路:选择最左或者最右为key,定义两个指针prev和cur分别指向序列开头,prev下一个位置。然后向后走,如果遇到比key小的cur走,prev也向后走。直到遇到比key大的,只有cur走,prev不走,当再次遇到比key小的,prev先走,然后交换此时cur和prev的值,cur再走。重复上面步骤,直到cur走到序列尾,然后交换prev和key的值。通过上面操作我们可以让cur和prev中间的值为比key大的,此方法就是把比key大的往后推,小的往前移。

步骤:1.选择最左key,prev和cur分别指向序列开头,开头下一个

           2.cur先走,prev后走

           3.遇到比key大的,只有cur走

          4.再遇到key小的,prev先走,然后交换此时prev和cur的值,cur在走

          5.cur走到序列尾,交换prev和key的值

          6..分割序列,分为keyi前面的序列和keyi后面的位置,重复以上所有步骤。

动画图解如下:

//快速排序
//前后指针法
void QuickSort2(int* a, int left, int right) {
	
	if (left >= right)
		return;

	
	int prev = left, cur = left+1;

	int keyi = left;
	while (cur <= right)
	{    
        //如果遇到比key小的才交换
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
	keyi = prev;

    //分割[left,keyi-1] [keyi+1,right]
	QuickSort2(a, left, keyi - 1);
	QuickSort2(a, keyi+1, right);

}

2.6.3 非递归版本

思路:之前我们都是通过递归来解决的,我们需要的是排序的左右子区间,所以我们可以通过一个栈来存储排序的左右子空间,根据栈先进后出的特性。左右子区间依次进栈出栈从而达到递归的效果。

void QuickSortNonR(int* a, int left, int right) {
	ST st;
	StackInit(&st);
	
	//左右下标入栈
    //右边先进  左边后进
	StackPush(&st,right);
	StackPush(&st,left);

	while (!StackEmpty(&st))
	{

		left = StackTop(&st);
		StackPop(&st);

		right = StackTop(&st);
		StackPop(&st);

		//单趟
		int prev = left, cur = left + 1;

		int keyi = left;
		while (cur <= right)
		{
			if (a[cur] < a[keyi] && ++prev != cur)
			{
				Swap(&a[cur], &a[prev]);
			}
			cur++;
		}
		Swap(&a[prev], &a[keyi]);
		keyi = prev;

		//[left,key-1] && [key+1,right]
        
        //进左右子区间
		if (keyi + 1 < right)
		{
			StackPush(&st, right);
			StackPush(&st, keyi + 1);
		}

		if (keyi - 1 > left)
		{
			StackPush(&st, keyi - 1);
			StackPush(&st, left);
		}
	}
	
	StackDestroy(&st);

}
快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
快速排序
时间复杂度: O(N*logN)
空间复杂度: O(logN)
稳定性:不稳定

2.7 归并排序

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

动画图解如下:
//归并排序
void _MergeSort(int* a, int begin, int end, int* temp) {
	//只有一个元素就返回
    if (begin == end)
		return;

    //从中间开始分割
	int mini = (begin + end) / 2;

    //指向两个序列起始位置
	int begin1 = begin, end1 = mini;
	int begin2 = mini + 1, end2 = end;

    
	_MergeSort(a, begin1, end1, temp);
	_MergeSort(a, begin2, end2, temp);
	
    //单趟
    //选下的插入到新的序列中
	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, temp + begin, sizeof(int) * (end - begin + 1));

}

void MergeSort(int* a, int n) {

    //开辟新的序列
	int* temp = (int*)malloc(sizeof(int) * n);
	if (temp == NULL)
	{
		perror("malloc fail");
		return;
	}
	
	_MergeSort(a, 0, n-1, temp);

	free(temp);
	temp = NULL;

}

非递归版本

我们之前是用递归先进行单个排序,在到组排。我们也可以不通过递归,通过回溯的思想,先定义一个gap,gap从1开始,即先单个为一组,然后两两排序,然后进行循环gap×2来进行gap数量为一组在进行归并。

void MergeSortNonR(int* a, int n)
{
	int* temp = (int*)malloc(sizeof(int) * n);
	if (temp == NULL)
	{
		perror("malloc fail");
		return;
	}

	int gap = 1;

	while (gap < n) 
	{
		for (int j = 0; j < n; j += gap * 2)
		{
            //两个区间的起始位置
			int begin1 = j, end1 = j + gap - 1;
			int begin2 = begin1 + gap, end2 = begin2 + gap - 1;
			
            //判断是否有越界

			if (end1 >= n || begin2 >= n)
				break;

			if (end2 >= n)
				end2 = n - 1;
			
			int i = j;

			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 + j, temp + j, sizeof(int) * (end2 - j + 1));
		}
		gap *= 2;
	}
	
	free(temp);
	temp = NULL;
}

归并排序

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

空间复杂度:O(N)

稳定性:稳定

2.8 计数排序

上面的排序,我们都是通过比较来排序的,而计数排序是非比较排序算法。
思路:遍历序列,找到最大最小的值,通过它们的差值来新开一个序列,在遍历序列,通过序列的值减去最小值作为下标在新开序列的位置计数。最后在遍历序列,该新序列有值则新序列的下标加最小值即为该序列上的值。
//计数排序
void CountSort(int* a, int n) {

	int max = a[0], min = a[0];

	for (int i = 0; i < n; i++)
	{
		if (a[i] > max)
			max = a[i];
		if (a[i] < min)
			min = a[i];
	}

	int range = max - min + 1;
	int* count = (int*)malloc(sizeof(int) * range);
	if (count == NULL)
	{
		perror("malloc fail");
		return;
	}

	memset(count, 0, sizeof(int) * range);

	//计数
	for (int i = 0; i < n; i++)
	{
		count[a[i] - min]++;
	}

	//排序
	int j = 0;
	for (int i = 0; i < n; i++)
	{
		while (count[i]--)
		{
			a[i] = i + min;
		}
	}
}

计数排序

时间复杂度:O(N+range)
空间复杂度:O(range)

三、算法性能

算法性能再不同场景下有不一样的性能,下图参考:

总结

上述文章,我们介绍了各种排序算法,希望对你有所帮助。

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

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

相关文章

5G图标显示分析

1、问题现象 MTK平台项目中出现一个5G图标显示问题&#xff0c;注册5G时&#xff0c;拨打电话&#xff0c;对比机图标显示回落到4G&#xff0c;测试机一直显示5G。 2、原因分析 2.1、NSA显示规则 根据GSMA协议&#xff0c;NSA架构下5G图标显示有如下4种. 2.2、Android中显示5G…

Idea报错:无法访问org.springframework.boot.SpringApplication

在开发项目时&#xff0c;常常会遇到这种问题&#xff0c;报错信息如下图所示 版本号与jdk版本号存在对应关系&#xff0c;61.0对应jdk17&#xff0c;52.0对应jdk8 所以是某个依赖的版本太高&#xff0c;降低该依赖的版本即可 具体步骤&#xff1a; ①修改pom.xml中spring b…

16册 | 移动机器人(自动驾驶)系列

此文档整理推荐了16本移动机器人&#xff08;自动驾驶&#xff09;相关的书籍&#xff0c;内容包括&#xff1a;ROS、机器人基础开发、分布式机器人控制、集群机器人控制、嵌入式机器人、多传感器融合等等。 学习&#xff0c;切勿急于求成&#xff0c;读书自学&#xff0c;需多…

⑥ - 后端工程师通识指南

&#x1f4d6; 该文隶属 程序员&#xff1a;职场关键角色通识宝典 ✍️ 作者&#xff1a;哈哥撩编程&#xff08;视频号同名&#xff09; 博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者 &#x1f3c6; 推荐专栏…

基于STM32单片机的心率、血氧、温度检测系统设计与实现

基于STM32单片机的心率、血氧、温度检测系统设计与实现 摘要&#xff1a;本文主要设计并实现了一个基于STM32单片机的心率、血氧和温度检测系统。该系统使用MAX30102传感器采集心率和血氧浓度&#xff0c;LMT70传感器用于温度检测&#xff0c;同时通过OLED显示屏展示实时数据。…

[BT]BUUCTF刷题第25天(4.28)

第25天&#xff08;共3题&#xff09; Web [CISCN 2019 初赛]Love Math 打开网站就是一段泄露的源代码&#xff1a; <?php error_reporting(0); //听说你很喜欢数学&#xff0c;不知道你是否爱它胜过爱flag if(!isset($_GET[c])){show_source(__FILE__); }else{//例子 c…

使用 xe2 调整 3dTileset 模型位置并获取模型矩阵 modelMatrix

使用 xe2 调整 3dTileset 模型位置并获取模型矩阵 modelMatrix Demo 获取改变后的模型的 modelMatrix src\examples\tile\edit\offset\index.html 目录下&#xff0c;设置 3dTileset 地址&#xff0c;拖动模型&#xff0c;监听 modelMatrix 变化。

Linux(Centos 7)环境下安装wget,并且更换阿里云镜像

Linux(Centos 7) Minimal 安装后&#xff0c;由于没有预装wget&#xff0c;在使用wget命令去下载安装相关应用时&#xff0c;提示&#xff1a;“wget: command not found” 先在Linux服务器窗口中&#xff0c;输入如下命令&#xff0c;检查Linux服务器有没有安装过wget。 rpm -…

ubuntu22.04 修改内核源码教程

1. 确认当前内核版本 uname -a 2. 去ubuntu官网下载对应版本内核源码 6.5.0-28.29 : linux package : Ubuntu (launchpad.net) 3. 准备编译环境 sudo apt-get install libncurses5-dev libssl-dev build-essential openssl flex bison libelf-dev tar -xzvf linux_6.5.…

【多模态大模型】AI对视频内容解析问答

文章目录 1. 项目背景2. 直接对视频进行解析进行AI问答&#xff1a;MiniGPT4-Video2.1 MiniGPT4-Video效果 3. 对视频抽帧为图片再进行AI问答3.1 视频抽帧3.2 图片AI问答3.2.1 阿里通义千问大模型 Qwen-vl-plus3.2.2 Moonshot 1. 项目背景 最近在做一个项目,需要使用AI技术对视…

Python 语音识别系列-实战学习-语音识别特征提取

Python 语音识别系列-实战学习-语音识别特征提取 前言1.预加重、分帧和加窗2.提取特征3.可视化特征4.总结 前言 语音识别特征提取是语音处理中的一个重要环节&#xff0c;其主要任务是将连续的时域语音信号转换为连续的特征向量&#xff0c;以便于后续的语音识别和语音处理任务…

qt学习篇---C++基础学习

本学习笔记学习下面视频总结&#xff0c;感兴趣可以去学习。讲的很详细 【北京迅为】嵌入式学习之QT学习篇_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1tp4y1i7EJ/?spm_id_from333.337.search-card.all.click&vd_source8827cc0da16223b9f2ad8ae7111de9e2 目录 C…

Spring ai 快速入门及使用,构建你自己的ai

第一步&#xff1a;创建springboot项目 jdk必须是17及以上 1.8用不了 第二步 选择web和ai的依赖 选择openai 第三步 需要配置openai key 配置 分享个免费或的apikey的地方New API 会免费赠送1刀的token spring.application.namespringAI spring.ai.openai.base-urlhttps://ap…

封装形式,进化,DIP封装及键出方法

本文主要讨论芯片封装的主要形式&#xff0c;概念&#xff0c;以及芯片封装的演化&#xff0c;最后以DIP封装为例&#xff0c;分析键出方式。 1-IC封装的形式 IC 封装是指将组成电子器件的各个组成部分&#xff0c;包括半导体芯片、基板、管脚连接线等&#xff0c;按照要求布局…

【maven】pom文件详解和延伸知识

【maven】pom文件详解 【一】maven项目的pom文件详解【1】maven项目的目录结构【2】根元素和必要配置【3】父项目和parent元素【4】项目构建需要的信息【5】项目依赖相关信息&#xff08;1&#xff09;依赖坐标&#xff08;2&#xff09;依赖类型&#xff08;3&#xff09;依赖…

文件上传安全以及防止无限制文件上传

文件上传安全以及防止无限制文件上传 在网络应用中&#xff0c;文件上传是一项常见功能&#xff0c;用户可以通过它上传图片、文档或其他媒体文件。然而&#xff0c;如果没有适当的安全措施&#xff0c;文件上传功能可能成为安全漏洞的源头。本文将探讨文件上传过程中的安全风…

在网站源码后台增加响应式布局

一本教材上的网站源码&#xff0c;后台在手机上查看还是按照电脑的页面样式&#xff0c;不方便查看和发布新内容。教材上讲了响应式布局。对于页面结构简单的网站&#xff0c;可以利用响应式&#xff0c;使页面自动适用各种屏幕的分辨率。 今天在一个网站源码的后台使用了响应…

夸克网盘免费领取1TB空间的方法

夸克网盘背靠阿里这颗大树&#xff0c;经历了这两年的发展&#xff0c;用户规模早已是千万级体量&#xff0c;用户体验个人也觉得非常不错&#xff0c;并且在日臻完善的路上&#xff0c;必会越走越远。现在已经不能领取一个月会员&#xff0c;也没有了2TB免费空间的说法&#x…

基于python-flask技术的社区信息交流平台【数据库+15000文档】

预览 介绍 系统只需使用者通过电脑浏览器即可实现系统的访问和操作的WEB模式的信息化系统。为了保证系统数据的准确性、安全性的数据存储&#xff0c;系统应用MySQL数据库进行系统数据存储服务。根据对社区工作的深入调研和对社区居民的走访调查&#xff0c;详细分析整体系统的…

vue2左侧菜单栏收缩展开功能

目录 1. Main.vue页面代码 a. 修改侧边栏属性 b. 修改头部导航栏 c. 定义我们的变量 d. collapse函数 2. Header.vue页面代码 3. Aside.vue页面代码 vue2左侧菜单栏收缩展开目前是非常常见的&#xff0c;我们在日常开发过程中经常会碰到。这一小节我们就详细了解一下这个…