排序算法大总结(插入、希尔、选择、堆、冒泡、快速、归并、计数)

news2024/11/24 17:08:01

在这里插入图片描述

  • 1. 排序概要
  • 2. 插入排序
    • 直接插入排序
    • 希尔排序(缩小增量排序)
  • 3.选择排序
    • 直接选择排序
    • 堆排序
  • 4. 交换排序
    • 冒泡排序
    • 快速排序
      • 霍尔版本(hoare)
      • 挖坑法
      • 双指针版本
      • 快排优化
      • 快速排序非递归
  • 5. 归并排序
    • 归并递归版本
    • 归并非递归版本
  • 6.计数排序

1. 排序概要

排序: 就是将一串随机数据,按照从小到大、或者从大到小重新排列一遍,使它变成有序的数据,便于人们观察和提取数据。

常见的排序算法有:插入排序、选择排序、交换排序、归并排序。

2. 插入排序

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。

直接插入排序

当插入第i(i>=1)个元素时,前面的arr[0],arr[1]…arr[i-1]已经排好序,此时用arr[i]的排序码与前面的arr进行比较,找到插入位置就将arr[i]插入,原来位置上的元素,顺序后移。

//插入排序
void InsertSort(int* a, int n)
{
	//从头往后开始遍历
	for (int i = 0; i < n - 1; i++)
	{
		int end = i;
		int key = a[end + 1];  //保存最后的值
		while(end>=0)
		{

			//比前边小就交换
			if (key < a[end])
			{
				//前面的给后面
				a[end + 1] = a[end];
			}
			else
			{
				break;
			}
			end--;
		}
		a[end + 1] = key;
	}

}

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

希尔排序(缩小增量排序)

先选取一个步长gap,把每隔gap长度的数据分成一个个组,所有相距为gap的数据在同一个组,并且对每组的数据进行插入排序,然后缩小gap,重复上述过程,直至gap为1,当gap为1时,所有记录在统一组内排好序。

//希尔排序
void ShellSort(int* a, int n)
{
	int gap = n;
	//gap>1,预排
	//gap ==1 ,插入排序
	while (gap > 1)
	{
		gap = (gap / 3) + 1;
		for (int i = 0; i < n - gap; i++)
		{
			//单次排序调整
			int end = i;
			int key = a[end + gap];
			while (end >= 0)
			{
				if (key < a[end])
				{
					a[end + gap] = a[end];
				}
				else
				{
					break;
				}
				end -= gap;
			}
			a[end + gap] = key;
		}
	}
}

特性总结:
1.希尔是对直接插入排序的优化。
2.当gap>1时是预排序,目的是让数组更接近有序。当gap==1时,数组已经接近有序,这样就会很快。预排序可以让大数更快的走向末尾,小数更快的走向开始。
3.时间复杂度:接近于O(N^1.3)
4.空间复杂度:O(1)
5.稳定性:不稳定

3.选择排序

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

直接选择排序

在元素集合0~i-1中找到最小的元素,记住数组元素的下标,若遍历完后,该数组下标的位置不是当前数组的起始位置,则该元素与起始位置交换,重复上述步骤,直到集合剩余一个元素。

//选择排序
void SelectSort(int* a, int n)
{
	//每次选择最大和最小的
	int begin = 0;
	int end = n - 1;

	while (begin < end)
	{
		int min_index = begin;
		int max_index = begin;
		for (int i = begin; i <= end; i++)
		{
			//发现更小的
			if (a[min_index] > a[i])
			{
				min_index = i;
			}
			//发现更大的
			else if (a[max_index] < a[i])
			{
				max_index = i;
			}
		}
		Swap(&a[begin], &a[min_index]);
		//防止最大的数字被换走
		if (max_index == begin)
		{
			max_index = min_index;//把下标再赋回来
		}
		Swap(&a[end], &a[max_index]);
		end--;
		begin++;
	}

}


特性总结:
1.虽然思想很好理解,但是效率低,很少使用。
3.时间复杂度:O(N^2)
4.空间复杂度:O(1)
5.稳定性:不稳定

堆排序

堆排序是利用一种堆的数据结构来进行排序的算法,大堆排升序,小堆排降序,每次只选择堆顶的元素,作为最大值或最小值,直至堆的集合个数为1。

//堆排序(大堆)
//先建堆,从后往前建堆效率更高.
//向下建堆效率高,从后往前,每个结点的左右子树都建成堆
void AdjustDown(int* a, int n, int parent)
{
	//比较左右孩子较小的一个
	//如果条件满足再和父亲交换
	//再看调整的孩子需不需要
	int child = 2 * parent + 1;
	//有没有叶子结点
	while (child<n)
	{

        //右孩子存在,右孩子大于左孩子
        if (child + 1 < n && a[child] < a[child + 1])
        {
            child++;
        }
        //左孩子大于父亲
		if (a[child] > a[parent])
		{
			//孩子父亲交换,并且父亲变为孩子
			Swap(&a[child], &a[parent]);
			parent = child;
            child = 2*parent+1;
		}
		else
		{
			break;
		}
	}

}



//堆排序
void HeapSort(int* a, int n)
{
	//1.先建堆
	//2.然后交换首尾元素
	//再向下调整
	int parent = (n-1-1) / 2;
	while (parent>=0)
	{
		AdjustDown(a, n, parent);
		--parent;
	}
	int end = n-1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);//end是下标
		AdjustDown(a, end, 0); //end 代表个数
		--end;
	}
	
}

特性总结:
1.堆排序使用堆来选数字,效率提升很大
3.时间复杂度:O(NlogN)
4.空间复杂度:O(1)循环建堆
5.稳定性:不稳定

4. 交换排序

交换,根据序列中两个记录的键值的比较来对换这两个记录在序列中的位置。交换排序的特点是:将键值较大的数字向尾部移动,将键值较小的数字向序列的前部移动。

冒泡排序


//冒泡排序
void BubbleSort(int* a, int n)
{
	//从小冒到大
	//重复
	int flag = 0;
	for (int j = 0; j < n - 1; j++)
	{
		//每次排序完一个,将flag置0
		flag = 0;
		for (int i = 0; i < n - 1 - j; i++)
		{
			if (a[i] > a[i + 1])
			{
				flag = 1;
				Swap(&a[i], &a[i + 1]);
			}
		}
		if (flag == 0)
		{
			break;
		}
	}

}

特性总结:
1.时间复杂度:O(N^2)
2.空间复杂度:O(1)
3.稳定性:稳定

快速排序

递归思想:按照先序递归的方法,先找基准值,然后保证左子序列全部小于基准值,右子序列的值全部大于基准值。然后再次划分,直至子序列为1即可。

快速排序框架:

// 假设按照升序对array数组中[left, right)区间中的元素进行排序
void QuickSort(int array[], int left, int right)
{
 if(right - left <= 1)
 return;
 
 // 按照基准值对array数组的 [left, right)区间中的元素进行划分
 int div = partion(array, left, right);
 
 // 划分成功后以div为边界形成了左右两部分 [left, div) 和 [div+1, right)
 // 递归排[left, div)
 QuickSort(array, left, div);
 
 // 递归排[div+1, right)
 QuickSort(array, div+1, right);
}

霍尔版本(hoare)

左边作key,右边先走,找小,遇到小于key的数停下,然后左边走找大,遇到大于key的数停下,交换左右两个位置的数字,left==right。


问什么左边作key,右边先走呢?
要保证小于的位置比key小或者就是key的位置:1.R先走,R停下来,L去遇到R(因为R找的是小,R停下来的位置一定小于key);2.R先走,R没有找到比key小的值,R去遇到了L(相遇的位置是上一轮停下来的位置,要么就是key的位置,要么比key要小)

//快速排序(霍尔法)
void QuickSort_old_hoare(int* a, int begin, int end)
{
	//左边作key,右边先走找小,找到了停下
	//左边再走找大,找到停下,交换
	//重复

	if (begin >= end)
	{
		return;
	}

	//一次排序
	int left = begin;
	int right = end;
	int keyi = begin;
	while (left < right)
	{
		//找小
		while (left < right && a[keyi] <= a[right])
		{
			--right;
		}
		//找大
		while (left < right && a[left] <= a[keyi])
		{
			++left;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[left], &a[keyi]);
	keyi = left;

	//递归
	QuickSort_old_hoare(a, begin, keyi - 1);
	QuickSort_old_hoare(a, keyi+1, end);


}

函数分开版本:

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

	if (end-begin>10)
	{
		int keyi = Partition2(a, begin, end);
		QuickSort(a, begin, keyi - 1);
		QuickSort(a, keyi+1, end);
	}
	else
	{
		InsertSort(a + begin, end - begin + 1);
	}
}
//快排的霍尔版本
int Partition1(int* a, int begin, int end)
{
	int left = begin;
	int right = end;
	int keyi = begin;
	
	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[keyi], &a[left]);
	keyi = left;
	return keyi;

}

挖坑法

人们所熟知的快排就是这个思想,比霍尔法更容易清晰理解。先将第一个数放在临时变量key中,此时形成一个坑位,然后右边先走找小,遇到小的停下来,将该值赋给坑位,并形成一个新的坑位。并且左边找大,赋值,形成新的坑位,直至两边相遇,将key值赋给左边。


//快速排序(挖坑法)
void QuickSort_dig(int* a, int begin, int end)
{
	//左边作key,右边先走找小,找到了停下
	//左边再走找大,找到停下,交换
	//重复

	if (begin >= end)
	{
		return;
	}

	//一次排序
	int left = begin;
	int right = end;
	int keyi = GetMidIndex(a,left,right);
	int key = a[keyi];
	while (left < right)
	{
		//找小
		while (left < right && a[keyi] <= a[right])
		{
			--right;
		}
		a[keyi] = a[right];
		keyi = right;  //right变为坑
		//找大
		while (left < right && a[left] <= a[keyi])
		{
			++left;
		}
		a[keyi] = a[left];
		keyi = left;
	}
	a[keyi] = key;

	//递归
	QuickSort_old_hoare(a, begin, keyi - 1);
	QuickSort_old_hoare(a, keyi + 1, end);


}

函数分开版本:


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

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


//挖坑版本
int Partition2(int* a, int begin, int end)
{
	int left = begin;
	int right = end;
	//int keyi = begin;//坑在起始位置
	int keyi = GetMidIndex(a,begin,end);//坑在起始位置
	int key = a[keyi];
	while (left < right)
	{
		//找小
		while (left < right &&a[right] >= key)
		{
			--right;
		}
		a[keyi] = a[right];//填坑
		keyi = right;//换坑
		//找大
		while (left < right && a[left] <= key)
		{
			++left;
		}
		a[keyi] = a[left];//填坑
		keyi = left;//换坑
	}
	a[keyi] = key;
	return keyi;
}

双指针版本

这个版本利用双‘指针’,优化了代码结构,使代码变得更加简洁,但是代码的可读性变差。快指针的作用是找小,慢指针的作用是保留边界,两个指针中间是大数,以翻跟头的形式往前走。

//双指针版本
int Partition3(int* a, int begin, int end)
{
	//prev在起始位置,cur在下一个位置
	//判断cur,若cur小于prev,则prev+1交换
	//大于prev,cur++
	int prev = begin;
	int cur = prev + 1;
	int key = a[begin];

	while (cur <= end)
	{
		当prev+1 == cur时,如果再交换的话就浪费了
		//if (a[cur] < key )
		//{
		//	++prev;
		//	Swap(&a[cur], &a[prev]);
		//}
		//++cur;

		//当prev+1 == cur时,如果再交换的话就浪费了
		if (a[cur] < key&&++prev!=cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		++cur;
	}
	Swap(&a[begin], &a[prev]);
	return prev;
}


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

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

快排优化

为了防止最坏情况下爆栈,我们需要使用三数取中法来优化选择keyi的位置。这样递归的深度接近logN。

//为了防止最坏情况爆栈,我们可以用三数取中法来优化,keyi
// 三数取中法
int GetMidIndex(int* a, int begin, int end)
{
	int mid = (begin + end) / 2;
	if (a[begin] > a[mid])
	{
		if (a[mid] > a[end])
		{
			return mid;
		}
		else
		{
			if (a[end] > a[begin])
			{
				return begin;
			}
			else
			{
				return end;
			}
		}
	}
	else
	{
		if (a[end] < a[begin])
		{
			return begin;
		}
		else
		{
			if (a[end] > a[mid])
			{
				return mid;
			}
			else
			{
				return end;
			}
		}
	}
}

快速排序非递归

因为快排的思想接近于二叉树的先序遍历,因此我们可以考虑使用栈来模拟递归的过程。核心思想就是:利用栈来保存每次快排的区间。有点类似于层序遍历的方法。


//快排非递归(需要使用栈)
// 要求掌握,递归改非递归
// 递归大问题,极端场景下面,如果深度太深,会出现栈溢出
// 1、直接改循环 -- 比如斐波那契数列、归并排序
// 2、用数据结构栈模拟递归过程
void QuickSort_nonrecursive(int* a, int begin, int end)
{
	//先将左右入栈
	//出栈,调用快排函数
	//调用完了再入栈
	Stack q;
	StackInit(&q);
	StackPush(&q, end);
	StackPush(&q, begin);

	//栈不空
	while (!StackEmpty(&q))
	{
		int left = StackTop(&q);
		StackPop(&q);
		int right = StackTop(&q);
		StackPop(&q);
		如果左小于右说明可以划分,就继续入栈
		//if (left < right)
		//{
		//	int keyi = Partition2(a, left, right);
		//	StackPush(&q, keyi - 1);
		//	StackPush(&q, left);
		//	StackPush(&q, right);
		//	StackPush(&q, keyi + 1);
		//}
		

		int keyi = Partition2(a, left, right);
		//小区间能继续划分,就入栈
		if (left < keyi - 1)
		{
			StackPush(&q, keyi - 1);
			StackPush(&q, left);
		}
		if (keyi + 1 < right)
		{
			StackPush(&q, right);
			StackPush(&q, keyi + 1);
		}


	}
	StackDestroy(&q);
}

特性总结:
1.快排,顾名思义综合性能最好,适应场景最多
2.时间复杂度:O(NlogN)
3.空间复杂度:O(logN)
4.稳定性:不稳定

5. 归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法采用分治法(Divide and Conquer)。将已有序的子序列合并,得到完全有序的序列;即先保证子序列有序,然后将两个子序列合并成一个有序序列,称为二路归并。核心步骤:先分解、后合并。

归并递归版本

// 归并排序递归

void MergeSort(int* a, int n)
{
	int* tem = (int*)malloc(sizeof(int) * n);
	if (tem == NULL)
	{
		printf("malloc failed");
		exit(0);
	}

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

	free(tem);
}
void _MergeSort(int* a, int begin, int end, int* tem)
{
	//begin和end左闭右闭区间
	if (begin >= end) //只有一个元素就不需要归并了
	{
		return;
	}

	//1.分解
	int mid = (begin + end) / 2;
	_MergeSort(a, begin, mid, tem);
	_MergeSort(a, mid+1, end, tem);

	//2.合并(都是闭区间)
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1, end2 = end;
	int j = begin;
	//开始合并
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tem[j++] = a[begin1++];
		}
		else
		{
			tem[j++] = a[begin2++];
		}
	}
	while (begin1 <= end1)
	{
		tem[j++] = a[begin1++];
	}
	while (begin2 <= end2)
	{
		tem[j++] = a[begin2++];
	}

	//合并好一部分就拷贝回去,左闭右闭加1
	memcpy(a + begin, tem + begin, sizeof(int) * (end - begin + 1));

}

归并非递归版本

因为归并的递归类似于后续遍历,因此不适合用栈来模拟实现,会导致丢失区间问题。因此我们考虑使用循环来修改。利用gap来遍历数组,模拟二路归并的过程,注意区间的控制问题(很棘手)

归并一次后同意合并:

// 归并排序非递归
//后序遍历用栈不好改非递归
//考虑用循环
//第一轮,一个一个排,第二轮两个两个排,
void MergeSortNonR(int* a, int n)
{
	int begin = 0;
	int end = n - 1;
	int* tem = (int*)malloc(sizeof(int) * n);
	assert(tem);
	memset(tem, 0, sizeof(int) * n);
	//排序
	int gap = 1;
	while (gap < n)
	{
		//printf("gap = %d: ", gap);
		for (int i = 0; i < n; i = i + 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = begin2 + gap - 1;

			//防止越界,修正边界
			//end1越界
			if (end1 >= n)
			{
				//把end1修成最后一个数
				end1 = n - 1;
				begin2 = n;
				end2 = n - 1;
			}
			else if(begin2 >= n)// begin2越界
			{
				begin2 = n;
				end2 = n - 1;
			}
			else if (end2 >= n) // end2越界
			{
				end2 = n - 1;
			}



			//printf("[%d,%d] [%d,%d]->", begin1, end1, begin2, end2);
			//往tem,排序
			int j = i;//比较位置开始,即从begin1
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] <= a[begin2])
				{
					tem[j++] = a[begin1++];
				}
				else
				{
					tem[j++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tem[j++] = a[begin1++];

			}
			while (begin2 <= end2)
			{
				tem[j++] = a[begin2++];
			}
	
		}
		//排完全部的再拷贝
		//合并
		//printf("\n");
		memcpy(a, tem, sizeof(int) * (end - begin + 1));
		gap = gap * 2;
	}

}

归并一个区间就合并:

// 归并排序非递归
//后序遍历用栈不好改非递归
//考虑用循环
//第一轮,一个一个排,第二轮两个两个排,
void MergeSortNonR(int* a, int n)
{
	int begin = 0;
	int end = n - 1;
	int* tem = (int*)malloc(sizeof(int) * n);
	assert(tem);
	memset(tem, 0, sizeof(int) * n);
	//排序
	int gap = 1;
	while (gap < n)
	{
		//printf("gap = %d: ", gap);
		for (int i = 0; i < n; i = i + 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = begin2 + gap - 1;

			//防止越界,修正边界
			//end1越界
			if (end1 >= n)
			{
				//把end1修成最后一个数
				end1 = n - 1;
				begin2 = n;
				end2 = n - 1;
			}
			else if (begin2 >= n)// begin2越界
			{
				begin2 = n;
				end2 = n - 1;
			}
			else if (end2 >= n) // end2越界
			{
				end2 = n - 1;
			}
			//记录每次归并几个,就拷贝几个
			int count = end2 - begin1 + 1;

			//printf("[%d,%d] [%d,%d]->", begin1, end1, begin2, end2);
			//往tem,排序
			int j = i;//比较位置开始,即从begin1
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] <= a[begin2])
				{
					tem[j++] = a[begin1++];
				}
				else
				{
					tem[j++] = a[begin2++];
				}
			}
			while (begin1 <= end1)
			{
				tem[j++] = a[begin1++];

			}
			while (begin2 <= end2)
			{
				tem[j++] = a[begin2++];
			}
			//排完一部分就拷贝
			memcpy(a + i, tem + i, sizeof(int) * count);

		}

		gap = gap * 2;
	}

}

特性总结
1.缺点空间复杂度为O(N),该算法主要用于外部排序的思想。
2.时间复杂度:O(NlogN)
3.空间复杂度:O(N)
4.稳定性:稳定

6.计数排序

计数排序又称鸽巢原理,类似于哈希定址法:第一次统计数值出现的次数,根据统计的结果将序列回收到原来的序列中。

//计数排序
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 count = max - min + 1;
	int* tem = (int*)malloc(sizeof(int) * count);
	assert(tem);
	memset(tem, 0, sizeof(int) * count);

	//遍历数组记录数据出现次数
	for (int i = 0; i < n; i++)
	{
		tem[a[i] - min]++;
	}

	int j = 0;
	//排序,tem中出现几次就往a写几个
	for (int i = 0; i < count; i++)
	{
		//只要tem[i]不为0,就会进入循环
		while (tem[i]--)
		{
			a[j++] = i + min;
		}
	}
}

特性总结
1.计数排序在数据范围集中时,效率很高,但不适合浮点数,数据范围相差太大的数据。
2.时间复杂度:O(max(N,range))
3.空间复杂度:O(range)
4.稳定性:稳定

以上就是本文对排序知识的总结,如有问题,欢迎在评论区讨论。

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

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

相关文章

物联网开发项目中具备哪些特点?

物联网开发是一项由设备、传感器、系统和应用程序组成的复杂技术。许多公司已经制定了计划&#xff0c;准备将物联网技术整合到他们的系统中&#xff0c;以帮助提高效率和生产力。在许多方面&#xff0c;物联网都是一项技术投资&#xff0c;但与其他投资相比&#xff0c;它可以…

RFID如何提升工业物流管理效率?

RFID技术目前已经在工业物流行业中广泛应用&#xff0c;企业只要将附带产品信息的RFID标签贴在货物上&#xff0c;利用工业读写器&#xff0c;可以快速准确地读取货物信息&#xff0c;提高仓库管理效率。 RFID如何提升工业物流管理效率? 1、跟踪货物 RFID技术可帮助企业跟踪货…

声表面波滤波器圆片级互连封装技术研究

陈作桓&#xff0c;于大全&#xff0c;张名川 厦门大学&#xff0c;厦门云天半导体科技有限公司 摘要 射频前端模块是无线通信的核心&#xff0c;滤波器作为射频前端的关键器件&#xff0c;可将带外干扰和噪声滤除以保留特定频段内的信号&#xff0c;满足射频系统的通讯要求…

B站刚崩,唯品会又崩:亿级用户网站的架构硬伤与解决方案

说在前面 在40岁老架构师尼恩的数千读者的社区中&#xff0c;一直在指导大家简历和职业升级。前几天&#xff0c;指导了一个华为老伙伴的简历&#xff0c;小伙伴的优势在异地多活&#xff0c;但是在简历指导的过程中&#xff0c;尼恩发现&#xff1a; 异地多活的概念、异地多活…

Segment Anything模型用于地理空间数据

原文地址&#xff1a;https://samgeo.gishub.org/examples/satellite/ 此笔记本通过几行代码展示了如何使用 Segment Anything Model (SAM) 来使用分段卫星图像。确保为此jupyter notebook使用 GPU 运行时。 安装依赖 取消注释并运行以下单元格以安装所需的依赖项。 # %pip ins…

如何批量删除文件名称中的内容

网上有很多&#xff0c;这里自己要用就整理一下。 最好的还是知乎大佬张三丰的方式&#xff0c;放在参考内第一个链接。 首先打开命令行提示符 另一种方式按住WinR 输入powershell 弹出窗口&#xff1a; 我这里为了展示&#xff0c;在C盘新建了一个文件夹命名为1 里面新建了…

比起各式各样的AI应用,我们可能更需要AI for OS

刚刚过去的五月&#xff0c;是一个炙热的AI之夏。前有2023谷歌 I/O开发者大会“炸场”&#xff0c;开建AI全宇宙&#xff0c;后有2023微软Build大会&#xff0c;一切都与AI相关。 AI被谷歌和微软应用到各个产品&#xff0c;落地速度一路狂飙。不过&#xff0c;应用层面&#xf…

开启未来科技之门:选择IT相关专业,迈向成功的高考生小贴士!

毕业在即&#xff0c;许多即将高考的学生正面临选择未来专业的重要决策。在当今数字化时代&#xff0c;IT行业成为一个备受瞩目的领域&#xff0c;为学生们提供了广阔的就业前景和丰富的发展机会。本文将为高考生提供一些关于选择IT相关专业的小贴士&#xff0c;以帮助他们做出…

写对二分查找不是套模板并往里面填空,需要仔细分析题意

视频讲解&#xff1a;《算法不好玩》二分查找专题 &#xff08;已经录制的部分&#xff0c;能够帮助大家完全搞懂二分查找算法&#xff0c;非常适合初学的朋友们&#xff09;。 2022 年 12 月 27 日补充&#xff1a;有时间的话请大家先看上面的视频&#xff0c;2 倍速看完就好…

JAVA基础 - 使用CommandLine解析命令行参数

它是什么 commons-cli 是一个强大而的开源的命令行参数传递与解析的解决方案&#xff0c;用于接收MAIN方法的args参数。可以通过设置短选项&#xff08;即选项名简写&#xff09;、长选项&#xff08;即全写&#xff09;、设置是否需要携带选项参数&#xff08;指定为 false 时…

jenkins python api与json api不同

查看jenkins的python api与json api&#xff0c;感觉两者相差不多&#xff0c;但还是有所区别&#xff0c;所以用BeyondCompare进行对比分析。 1、jenkins base url的api对比 左侧的为&#xff1a;http://server:port/jenkins/api/python?prettytrue 右侧的为&#xff1a;h…

提示工程师指南4-ChatGPT Prompt Engineering

ChatGPT Prompt Engineering 在这个部分&#xff0c;我们将介绍 ChatGPT 的最新提示工程技术&#xff0c;包括技巧、应用、限制、论文和额外的阅读材料。 主题&#xff1a; 与 ChatGPT 对话 Python 笔记本 请注意&#xff0c;本部分正在紧密开发中。 文章目录 ChatGPT Promp…

【爬虫】3.4 爬取网站复杂数据

1. Web服务器网站 进一步把前面的Web网站的mysql.html, python.html, java.html丰富其中 的内容&#xff0c;并加上图形&#xff1a; mysql.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>my…

手把手教你看懂51单片机原理图

最近当了单片机课设的助教,又再次接触了51单片机。发现初学者还看不太原理图&#xff0c;不能理解单片机 led灯&#xff0c;蜂鸣器&#xff0c;数码管是怎么操作的。现在结合原理图讲解一下怎么操作这些外设模块&#xff01;我们就以一些初始化代码进行讲解。 注&#xff1a;这…

开始使用Vue 3时应避免的10个错误

本文首发于微信公众号&#xff1a;大迁世界, 我的微信&#xff1a;qq449245884&#xff0c;我会第一时间和你分享前端行业趋势&#xff0c;学习途径等等。 更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi &#xff0c;包含一线大厂面试完整考点、资料以及我的…

华为OD机试真题 Java 实现【在字符串中找出连续最长的数字串】【2023 B卷 100分】,附详细解题思路

一、题目描述 输入一个字符串&#xff0c;返回其最长的数字子串&#xff0c;以及其长度。 若有多个最长的数字子串&#xff0c;则将它们全部输出&#xff08;按原字符串的相对位置&#xff09;。 本题含有多组样例输入。 数据范围&#xff1a; 字符串长度 1≤n≤200 &…

Linux进程懂了吗?一分钟快速上手

这里写目录标题 Linux进程介绍显示系统执行的进程终止进程查看进程树pstreeLinux进程作用 Linux进程介绍 Linux进程是计算机中正在运行的程序的实例。在Linux系统中&#xff0c;每个进程都有一个唯一的进程ID&#xff08;PID&#xff09;&#xff0c;用于标识该进程。&#xf…

Eigen中用于特征值分解的几个类的介绍

本文参考于 https://eigen.tuxfamily.org/dox/group__TopicLinearAlgebraDecompositions.html 很多场合我们需要去计算矩阵的特征值与特征向量&#xff0c;但是Eigen中有好几个计算特征值与特征向量的方法&#xff0c;这些方法到底该选哪个呢&#xff1f;这篇文章就带着大家来…

「企业技术架构」EA874:技术架构的原则和标准

企业技术架构中EA原则的应用 原则经常是正式EA工作的一部分。它们在个人决策和广泛适用且独立于具体决策的基本业务目标之间提供了更强的联系。原则是组织为激发最佳行为而选择的准则或最佳实践。它们很可能&#xff08;在最高级别&#xff09;被追溯到基本的业务需求和策略。如…

【MySQL数据库 | 第八篇】DML操作

目录 ​编辑 &#x1f914;前言&#xff1a; &#x1f914;DML介绍&#xff1a; &#x1f914;语法详情&#xff1a; &#x1f600;1.插入数据&#xff1a; 特点&#xff1a; 1.给指定字段添加数据&#xff1a; 代码示例: 运行结果&#xff1a; 2.给所有的字段添加数据&…