排序算法(C语言版)

前言

排序作为生产环境中常见的需求之一,对整个产品有举足轻重的影响,可以说使用一个合适的排序算法是业务逻辑中比较重要的一部分。今天我们就来介绍常见的排序算法以及实现

排序

所谓排序无非就是按照特定的规则对一组数据就行顺序化。

常见的排序有升序和降序。

对于数字类型的数据常见的规则是按照其大小排序。如果学过Java的朋友应该知道,Java引入了对象的概念,对象的排序规则一般需要程序员自己定义,实现Comparable或者Comparator接口,在在接口内部实现排序的逻辑

除排序本身的定义外,我们还需要了解一点关于排序的性质

  • 稳定性:当“大小”一致的两个数据应该如何规定两者的顺序呢?比如一个班级中有两位考100分的同学,我们应该如何规定两者的顺序呢?显然,一个常见的想法是谁先交卷谁是第一名。这种保证“交卷顺序”的排序算法,我们可以描述为稳定的排序算法。稳定性即保证排序后“大小”一致的数据顺序与排序前一致
  • 内/外排序:这是一组相对的概念。内部排序要求排序的数据全部在内存中完成排序。外部排序要求排序的数据在硬盘内存中移动来完成排序,常用于数据量巨大或者内存不够的时候使用。

常见的排序算法

常见的排序算法有比较类的排序:冒泡排序,插入排序,希尔排序,选择排序,堆排序,快速排序,归并排序

非比较类的排序:基数排序,计数排序,桶排序

下面我们就一个一个来了解上述算法的思想和代码实现,以下笔者均以排升序举例。

笔者在排序算法的实现中可能会用到交换算法,在这里先实现,后面不在介绍

//交换元素
void swap(int* p1, int* p2) {
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

这里是一个简答的交换,我们只是把它封装一层,实现代码的复用

冒泡排序

冒牌排序,思路是相邻两个数据就行比较,遍历一遍为一趟排序。一趟排序后可以保证本趟最大值位于合适的位置。由此,每趟排序后下一趟的比较次数可以优化。也可以定义一个标记,如果本趟没有交换,整个序列均有序

实现

//冒泡排序
void BubbleSort(int* a, int n);

void BubbleSort(int* a, int n)
{
	for (int y = 0; y < n - 1; y++)
	{
		int flag = 1;
		int len = n - y;
		for (int i = 0; i < len - 1; i++)
		{
			if (a[i] > a[i + 1])
			{
				swap(a + i + 1, a + i);
				flag = 0;
			}
		}
		if (flag) return;
	}
}

1. 冒泡排序是一种非常容易理解的排序
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:稳定

插入排序

插入排序,思路是假设前n个数据已经有序,第n+1个数据插入到有序的序列中。这个算法的适应性很强

实现

//插入排序
void InsertSort(int* a, int n);

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

1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:稳定
 

希尔排序

希尔排序是对插入排序的优化。插入排序的缺陷在于,在将降序排序成升序时,后面的较小值越来越难以移动到前面的位置,因为移动的次数由1,2,3……往上自增。希尔排序的优化在于增加跨度的方让序列更快的接近有序。 引入一个gap变量,即数据分为gap组,以组为单位进行插入排序。不断改变gap的值,有两个常用的gap算式 gap=gap/2 和 gap=gap/3+1。这两个算式均可以保证最后一次gap为1,即保证最后一次希尔排序转换为插入排序(此时序列接近有序,前面介绍插入排序时介绍插入排序的适应性很强,表现在排序一个接近有序的序列时效率很高)。当然也可以自定义gap算式,但是需要保证gap最后一次的取值是1

实现

//希尔排序
void ShellSort(int* a, int n);

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		int i = 0;
		while (i < gap)
		{
			int y = i;
			while (1)
			{
				if (y >= n || y + gap >= n)
					break;
				if (a[y + gap] < a[y]) {
					int x = y;
					int tmp = a[y + gap];
					while (x >= 0 && tmp < a[x])
					{
						a[x + gap] = a[x];
						x -= gap;
					}
					a[x + gap] = tmp;
				}
				y += gap;
			}
			i++;
		}
	}
}

1. 可以理解为gap!=1时是预排序,gap=1时是插入排序。希尔排序是对插入排序的优化
2. 时间复杂度:O(N^1.3)
3. 空间复杂度:O(1)
4. 稳定性:不稳定

选择排序

选择排序是一个比较简单的排序算法,主要的逻辑就是每一趟找出最小的值,和本趟开头位置的元素呼唤。这里可以有一点优化,就是在一趟遍历的时候,同时找最大值和最小值。

实现

这里我们提供两个版本的实现,优化和非优化的版本(说是优化,其实性能并没有提升多少)

//选择排序
void SelectSort(int* a, int n);//优化版,同时选择大小
void SelectSort1(int* a, int n);//只选择小

void SelectSort1(int* a, int n)//取小交换
{
	for (int y = 0; y < n - 1; y++) {
		int i = y;
		int tmp = y + 1;
		for (; tmp < n; tmp++)
		{
			if (a[tmp] < a[i])
				i = tmp;
		}
		swap(a + i, a + y);
	}
}
void SelectSort(int* a, int n)//优化,取大小交换
{
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int min = begin;
		int max = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			if (a[i] < a[min])
				min = i;
			else if (a[i] > a[max])
				max = i;
		}
		swap(a + begin, a + min);
		if (begin == max)
			max = min;
		swap(a + end, a + max);
		begin++;
		end--;
	}
}

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

堆排序

堆排序是依赖于堆这个数据结构实现的一种排序算法。什么是堆这里不再展开。我们想要用堆排序算法实现升序,需要用所有的数据建立一个大根堆,然后不断的pop堆顶的元素与堆末尾(逻辑上是堆,实际上是数组)元素交换,调整堆……知道堆中只剩一个元素,此时排序完成。

实现

//堆排序
void HeapSort(int* a, int n);

void xiangXiaTiaoZheng(int* arr, int pr, int k) {//向下调整
	int ch = pr * 2 + 1;
	while (ch < k) {
		if (ch + 1 < k && arr[ch + 1] > arr[ch]) ch++;
		if (arr[ch] > arr[pr]) {
			swap(arr + ch, arr + pr);
			pr = ch;
			ch = pr * 2 + 1;
		}
		else return;
	}
}
void jianDui(int* arr, int k)//建堆
{
	for (int i = (k - 2) / 2; i >= 0; i--) {
		xiangXiaTiaoZheng(arr, i, k);
	}
}
void HeapSort(int* a, int n)
{
	jianDui(a, n);
	int end = n - 1;
	while (end > 0) {
		swap(a, a + end);
		xiangXiaTiaoZheng(a, 0, end);
		end--;
	}
}

1. 堆排序使用堆来选数,效率就高了很多(topK问题)。向下调整建堆的算法要比向上调整建堆的算法效率高
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(1)
4. 稳定性:不稳定
 

快速排序

快速排序的思想是以每趟开始的元素为基准,将大于基准的元素放在基准数的右边,将小于基准的元素放在基准的左边,此时可以保证基准位于合适的位置。然后再分别处理基准的左半边和右半边,知道所有的元素都位于合适的位置上。

我们可以将实现分类为递归实现和非递归实现

递归实现

递归实现的大体逻辑是相同的,只不过在每一趟的实现有可以分为不同的版本。这里我们介绍三种不同的实现方式——hoare版本、挖坑版本、双指针版本

hoare版本

这里单趟的逻辑是以左侧开始位置的元素为基准元素,右边开始向左遍历在第一个小于基准元素的位置停下,左边开始向右遍历在第一个大于基准元素的位置停下,交换左右的元素,以上逻辑循环直到左右相遇,退出循环再交换相遇位置和起始位置的元素。

void QuickSort(int* a, int begin, int end);//hoare版本

void QuickSort(int* a, int begin, int end)//hoare版本
{
	if (begin >= end)
		return;
	/*
    if ((end - begin + 1) < 10)
	{
		InsertSort(a + begin, end - begin + 1);
		return;
	}
	int z = QuZhong(a, begin, end);
	swap(a + begin, a + z);
    */
	int tmp = a[begin];
	int left = begin;
	int right = end;
	while (left < right)
	{
		while (left < right && a[right] >= tmp)
		{
			right--;
		}
		while (left < right && a[left] <= tmp)
		{
			left++;
		}
		swap(a + left, a + right);
	}
	swap(a + begin, a + left);
	QuickSort(a, begin, left - 1);
	QuickSort(a, left + 1, end);
}

此版本是最初实现快速排序是使用的版本。

为了方便理解,后面再开发出双指针法和挖坑法

挖坑版本

挖坑法单趟的思路是以左侧开始位置的元素为基准元素,同时将左侧开始位置的元素记录到tmp中,设置此位置为坑。右边开始向左遍历在第一个小于基准元素的位置停下,将此位置的元素放到坑中,再将此位置设置为坑。将左边开始向右遍历在第一个大于基准元素的位置停下,将此位置的元素放到坑中,再将此位置设置为坑。以上逻辑循环直到左右相遇,退出循环,此时相遇的位置是坑位,将tmp添入坑位中

void QuickSort1(int* a, int begin, int end);//挖坑法版本

void QuickSort1(int* a, int begin, int end)
{
	if (begin >= end)
		return;
    /*
	if ((end - begin + 1) < 10)
	{
		InsertSort(a + begin, end - begin + 1);
		return;
	}
	int z = QuZhong(a, begin, end);
	swap(a + begin, a + z);
    */
	int tmp = a[begin];
	int tmpi = begin;
	int left = begin;
	int right = end;
	while (left < right)
	{
		while (left < right && a[right] >= tmp)
		{
			right--;
		}
		if (left < right)
		{
			swap(a + tmpi, a + right);
			tmpi = right;
			left++;
		}
		while (left < right && a[left] <= tmp)
		{
			left++;
		}
		if (left < right)
		{
			swap(a + tmpi, a + left);
			tmpi = left;
			right--;
		}
	}
	QuickSort1(a, begin, left - 1);
	QuickSort1(a, left + 1, end);
}

双指针版本

以本趟开始位置的元素为基准元素。定义两个指针变量,第一个指针prev指向本趟开始的元素,第二个指针cut指向本趟的第二个元素。如果cut指向的元素小于等于基准,则prev指针+1,prev与cut元素交换,cut指针+1:否则cut指针+1。直到cut指向空指针,退出循环,将基准元素与prev指向的元素互换。

void QuickSort2(int* a, int begin, int end);//双指针版本

void QuickSort2(int* a, int begin, int end)
{
	if (begin >= end)
		return;
    /*
	if ((end - begin + 1) < 10)
	{
		InsertSort(a + begin, end - begin + 1);
		return;
	}
	int z = QuZhong(a, begin, end);
	swap(a + begin, a + z);
    */
	int prev = begin;
	int cut = begin + 1;
	int tmp = a[begin];
	while (cut <= end)
	{
		while (cut <= end && a[cut] <= tmp)
		{
			prev++;
			cut++;
		}
		while (cut <= end && a[cut] > tmp)
		{
			cut++;
		}
		if (cut <= end)
		{
			prev++;
			swap(a + prev, a + cut);
		}
	}
	swap(a + begin, a + prev);
	QuickSort2(a, begin, prev - 1);
	QuickSort2(a, prev + 1, end);
}

非递归实现

递归版本在内存的开销上有可能会造成栈溢出,此时改成非递归是常见的需求。该非递归的核心思路就是用栈模拟递归的过程,利用栈存储关键的信息。

非递归需要依赖于栈这个数据结构,这里也不在展开

栈:

#pragma once
#include <stdio.h>
#include <stdlib.h>

// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* _a;
	int _top;		// 栈顶
	int _capacity;  // 容量 
}Stack;

// 初始化栈 
void StackInit(Stack* ps);
// 入栈 
void StackPush(Stack* ps, STDataType data);
// 出栈 
void StackPop(Stack* ps);
// 获取栈顶元素 
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数 
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps);
// 销毁栈 
void StackDestroy(Stack* ps);

#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"

void StackInit(Stack* ps)
{
	ps->_a = NULL;
	ps->_top = -1;
	ps->_capacity = 0;
}

void StackPush(Stack* ps, STDataType data)
{
	if (ps->_capacity == 0) {
		ps->_a = (STDataType*)malloc(sizeof(STDataType) * 4);//默认初始化长度为4
		ps->_capacity = 4;
		ps->_top = 0;
	}
	else if (ps->_top == ps->_capacity)
	{
		ps->_capacity *= 2;
		ps->_a = (STDataType*)realloc(ps->_a, sizeof(STDataType) * ps->_capacity);//默认扩容至原先的两倍

	}
	(ps->_a)[ps->_top++] = data;
}

void StackPop(Stack* ps)
{
	if (ps->_top <= 0) return;
	ps->_top--;
}

STDataType StackTop(Stack* ps) {
	if (ps->_top <= 0) return 0;
	return (ps->_a)[--ps->_top];
}

int StackSize(Stack* ps)
{
	return ps->_top;
}

int StackEmpty(Stack* ps)
{
	if (ps->_top <= 0) return 1;
	return 0;
}

void StackDestroy(Stack* ps)
{
	free(ps->_a);
	ps->_a = NULL;
	ps = NULL;
}
void QuickSortNonR(int* a, int begin, int end);//非递归版本

void QuickSortNonR(int* a, int begin, int end) 	//非递归版本
{
	Stack sk;
	StackInit(&sk);
	StackPush(&sk, end);
	StackPush(&sk, begin);
	while (!StackEmpty(&sk))
	{
		int left = StackTop(&sk);
		int right = StackTop(&sk);
		int rembegin = left;
		int remend = right;
		int tmp = a[left];

		while (left < right)
		{
			while (left < right && a[right] >= tmp)
			{
				right--;
			}
			while (left < right && a[left] <= tmp)
			{
				left++;
			}
			swap(a + left, a + right);
		}
		swap(a + rembegin, a + left);
		if (left + 1 < remend) {
			StackPush(&sk, remend);
			StackPush(&sk, left + 1);
		}
		if (rembegin < left - 1) {
			StackPush(&sk, left - 1);
			StackPush(&sk, rembegin);
		}
	}
	StackDestroy(&sk);
}

优化

在此基础上可以对快速排序展开两个简单的优化

  • 小区间优化(当排序元素小于10可以转换为插入排序,减少递归的深度,减少开销)

将代码中注释的部分放开即可以实现小区间优化

  • 三数取中(避免出现向一边递归,算法退化为N^2的情况)
int QuZhong(int* arr, int first, int last)//优化,三数取中
{
	int z = (first + last) / 2;
	int a = arr[first];
	int b = arr[z];
	int c = arr[last];
	if (b > c)
	{
		if (c > a)
			return last;
		else
		{
			if (a < b)
				return first;
			else
				return z;
		}
	}
	else
	{
		if (b > a)
			return z;
		else
		{
			if (a < c)
				return first;
			else
				return last;
		}
	}
}

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

归并排序

归并排序是一种典型的分治思想,将大问题拆分成不能再分割的小问题。思路在将待排序不断对半分割分割,分割到不能再分割时将相邻两个组合并为一个有序的大组,再将两个相邻的两个大组合并为一个有序的大大组……

这里依然是提供两个版本的实现,递归版和非递归版

这里非递归的实现,是直接将单个元素视为递归下来不能再分割的最小单位,实现往上回归的部分

//归并排序
void MergeSort(int* a, int begin, int end);//递归版本
void MergeSortNonR(int* a, int begin, int end);//非递归版本

void MergeSort(int* a, int begin, int end)//归并排序
{
	int n = end - begin + 1;
	if (n < 2) return;
	int min = begin + n / 2;
	MergeSort(a, begin, min - 1);
	MergeSort(a, min, end);
	int* arr = (int*)malloc(sizeof(int) * n);
	int left = begin;
	int right = min;
	int i = 0;
	while (left < min && right <= end)
	{
		if (a[left] < a[right])
		{
			arr[i++] = a[left++];
		}
		else
		{
			arr[i++] = a[right++];
		}
	}
	if (left == min) {
		while (right <= end) {
			arr[i++] = a[right++];
		}
	}
	else
	{
		while (left < min) {
			arr[i++] = a[left++];
	 	}
	}
	i = 0;
	for (int y = begin; y <= end; y++)
	{
		a[y] = arr[i++];
	}
	free(arr);
}

void MergeSortNonR(int* a, int begin, int end)//非递归版本
{
	int gap = 1;
	int n = end - begin + 1;
	int* arr = (int*)malloc(sizeof(int) * n);
	while (gap < n)
	{
		for (int y = 0; y < n; y += gap * 2)
		{
			int left = y;
			int right = y + gap;
			if (right >= n) {
				for (int z = left; z < n; z++)
				{
					arr[z] = a[z];
				}
				break;
			}
			int i = y;
			int end1 = y + gap;
			int end2 = right + gap;
			if (end2 >= n)
				end2 = n;
			while (left < end1 && right < end2)
			{
				if (a[left] < a[right])
				{
					arr[i++] = a[left++];
				}
				else
				{
					arr[i++] = a[right++];
				}
			}
			if (left == end1) {
				while (right < end2) {
					arr[i++] = a[right++];
				}
			}
			else
			{
				while (left < end1) {
					arr[i++] = a[left++];
				}
			}
		}
		for (int z = 0; z < n; z++)
		{
			a[z] = arr[z];
		}
		gap *= 2;
	}
	free(arr);
}

1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(N)
4. 稳定性:稳定
 

计数排序

计数排序是一种非比较的排序,适用于对整数进行排序。思想是得到序列中的最大值和最小值,计算得到中间最多有多少个元素,遍历一遍序列,将元素映射到计数表中,再从计数表中依次读取出元素。

//计数排序
void CountSort(int* a, int n);

void CountSort(int* a, int n)
{
	int min = a[0];
	int max = a[0];
	for (int i = 1; i < n; i++)
	{
		if (a[i] < min)
			min = a[i];
		else if (a[i] > max)
			max = a[i];
	}
	int countN = max - min + 1;
	int* arr = (int*)calloc(countN, sizeof(int));
	for (int i = 0; i < n; i++)
	{
		arr[a[i] - min]++;
	}
	int y = 0;
	for (int i = 0; i < countN&&y<n; i++)
	{
		int sz = arr[i];
		while (sz--)
		{
			a[y++] = i + min;
		}
	}
}

1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
2. 时间复杂度:O(MAX(N,范围))
3. 空间复杂度:O(范围)
4. 稳定性:稳定

桶排序和基数排序

桶排序和基数排序不常用,这里只简单介绍思想不介绍具体实现

桶排序工作的原理是将数组分到有限数量的桶里。每个桶再分别排序,最后依次把各个桶中的记录列出来记得到有序序列

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较

排序算法的比较

 

 

结语

排序这部分重点掌握不同算法的思想,把握一趟是如何实现的,其他每一趟都是一样的思想

以上便是今天的全部内容。如果有帮助到你,请给我一个免费的赞。

因为这对我很重要。

编程世界的小比特,希望与大家一起无限进步。

感谢阅读!

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

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

相关文章

智能语音热水器:置入NRK3301离线语音识别ic 迈向智能家居新时代

一、热水器语音识别芯片开发背景 在科技的今天&#xff0c;人们对于生活品质的追求已不仅仅满足于基本的物质需求&#xff0c;更渴望通过智能技术让生活变得更加便捷、舒适。热水器作为家庭生活中不可或缺的一部分&#xff0c;其智能化转型势在必行。 在传统热水器使用中&#…

论文导读 | 事件因果关系抽取和识别

导读 目前&#xff0c;对事件因果关系的研究主要分为两类任务&#xff1a;事件因果关系识别&#xff08;Event Causality Identification&#xff0c;ECI&#xff09;和事件因果关系抽取&#xff08;Event Causality Extraction&#xff09;。事件因果关系识别旨在检测文本中两…

v5 实现动态时移播放

背景 有用户提出需要从当前时间前一段时间开始播放&#xff0c;比如 10s 前开始播放&#xff0c;或者 1 分钟前开始播放等。 在 v4 中有一个时光回溯功能&#xff0c;可以在配置中指定缓存时间&#xff0c;然后播放时可以指定 submode: 2来播放。 但是弊端是无法动态指定时间…

MySQL实训

项目名称与项目简介 股票交易系统是一个综合性的金融服务平台&#xff0c;它提供了股票买卖、交易查询、用户管理、股票信息管理以及资金账户管理等功能。系统旨在为用户提供一个安全、高效、便捷的股票交易环境&#xff0c;让用户能够实时掌握市场动态&#xff0c;做出合理的…

使用模板方法设计模式封装 socket 套接字并实现Tcp服务器和客户端 简单工厂模式设计

文章目录 使用模板方法设计模式封装套接字使用封装后的套接字实现Tcp服务器和客户端实现Tcp服务器实现Tcp客户端 工厂模式 使用模板方法设计模式封装套接字 可以使用模块方法设计模式来设计套接字 socket 的封装 模板方法&#xff08;Template Method&#xff09;设计模式是一…

CORE Mobility Errorr的调试

在运行CORE tutorial 3中的mobility示例时&#xff0c;出现如下错误&#xff1a; 当看到这个问题的时候&#xff0c;并没有仔细去分析日志和现象&#xff0c;在core-daemon的进程打印界面只看了一下最后的出错堆栈&#xff1a; 2024-06-27 10:43:48,614 - ERROR - _server:_ca…

微信小程序毕业设计-线上教育商城系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

无敌“水刊”,沾稿就收!5本机械工程方向SCI,100%录用,不退稿~评职/毕业首选~

在众多理工科专业中&#xff0c;计算机科学与人工智能、电子电气工程、机械工程、医学、土木工程、生物科学、化学工程以及数学与统计学等八个专业最吃香。 对于这些专业领域的毕业生和寻求职业晋升的在职人士而言&#xff0c;如何在学术界和工业界展现自己的研究成果和实力&am…

Type-C接口快充取电的优势及LDR6328的应用探讨

在当今这个快节奏的社会&#xff0c;电子设备已经成为我们生活中不可或缺的一部分。随着科技的不断发展&#xff0c;对于电子设备充电速度和效率的要求也越来越高。Type-C接口快充取电技术应运而生&#xff0c;以其独特的优势&#xff0c;成为了市场中的一股新势力。而LDR6328作…

家电品牌如何利用3D数字化技术,突破转型瓶颈?

家电行业正经历着从增量市场向存量市场的转变&#xff0c;用户的消费观念也日趋成熟&#xff0c;更加注重产品的体验和服务质量。无论是线上购物平台还是线下实体门店&#xff0c;提供个性化和增强体验感的产品与服务已成为家电市场未来发展的核心驱动力。 51建模网依托“3D数字…

手机如何录屏?小白也能秒变高手

随着智能手机的普及&#xff0c;手机录屏已经成为一种越来越普遍的需求。无论是录制游戏过程、分享操作教程&#xff0c;还是保留重要信息&#xff0c;手机录屏都发挥着重要作用。可是很多人不知道手机如何录屏&#xff0c;本文将介绍三种手机录屏方法&#xff0c;帮助大家轻松…

Java获取class对象3种方式,不同点解析。

Java获取class对象3种方式&#xff0c;不同点解析。 前言 Java获取class对象3种方式&#xff0c;不同点解析&#xff0c;他们是有区别的 创建目标类Apple进行演示&#xff01;&#xff01;&#xff01; OK&#xff01;结束&#xff01;我们就可以看出区别。

PH计仪器校准内容,以及相关注意事项内容

ph计大家一定不陌生&#xff0c;在日常生活中和实验场所&#xff0c;经常会有看到这种计量器具&#xff0c;作为测定ph值的常用仪器&#xff0c;其运用领域可谓十分广泛&#xff0c;不过因为其结构的特殊性&#xff0c;加上传感器的原理问题&#xff0c;其自身的计量校准也需要…

使用函数open()的例子

代码&#xff1a; #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main(void) {int fd-1;char filename[]"test.txt";fdopen(filename,O_RDWR);if(-1fd){printf("Open file %s failure!,fd…

六西格玛项目实战:数据驱动,手机PCM率直线下降

在当前智能手机市场日益竞争激烈的背景下&#xff0c;消费者对手机质量的要求达到了前所未有的高度。PCM&#xff08;可能指生产过程中的某种不良率或缺陷率&#xff09;作为影响手机质量的关键因素&#xff0c;直接关联到消费者满意度和品牌形象。为了应对这一挑战&#xff0c…

事务的概念-事务的概念、事务的定义(BEGIN TRANSACTION、COMMIT、ROLLBACK)

数据库系统中的事务&#xff0c;是保证系统在发生故障后或存在并发操作的情况下&#xff0c;数据库中的数据与企业业务结果相一致 一、事务的概念 在许多数据库应用系统中&#xff0c;数据库用来存储现实世界中一些企业的状态信息或其管理的数据 1、概念一 &#xff08;1&a…

OpenGL3.3_C++_Windows(22)

材质&#xff1a; 决定物体在渲染过程中最终视觉呈现的关键因素之一&#xff0c;它通过一系列光学&#xff08;投光物&#xff09;和物理参数&#xff08;反光度&#xff0c;反照率、金属度&#xff0c;折射率……&#xff09;准确模拟现实世界中的材料特性&#xff0c;从而增…

MySQL高级-索引-使用规则-单列索引联合索引

文章目录 1、单列索引2、联合索引3、查看表索引4、创建 name 和 phone 索引5、查询 phone17799990010 and name韩信6、执行计划 phone17799990010 and name韩信7、创建联合唯一索引 idx_user_phone_name8、再次执行计划 phone17799990010 and name韩信9、使用了USE INDEX提示来…

echarts/自定义 环形进度条,源码+图片 复制运行 自取

进度图1&#xff1a; <!--* FilePath: index.vue* Author: 是十九呐* Date: 2024-06-26 17:56:34* LastEditTime: 2024-06-27 10:16:20 --> <template><div class"pieChartProgress-container"><div class"pieChartProgress-chart" :…

【Python机器学习】自动化特征选择——基于模型的特征选择

基于模型的特征选择使用一个监督机器学习模型来判断每个特征的重要性&#xff0c;并且仅保留最重要的特征。用于特征学习的监督模型不需要与用于最终建模的模型相同。特征选择模型需要为每个特征提供某种重要性度量&#xff0c;以便用这个度量对特征进行排序。决策树和基于决策…