AI大模型教程
一起来学习

数据结构---排序算法(2)

二分查找(数组本身就是有序的):

非递归:

例如:

(1)先定位left和right,将数组一分为二,选取中间位置定为right

(2)比较中间位置和要寻找的数,如果中间位置大于要寻找的数则在中间数左边寻找要寻找的数

,如果中间位置小于要寻找的数则在中间数右边寻找要寻找的数

(3)如果中间位置大于要寻找的数则在中间数左边寻找要寻找的数,将right定位为中间位置加一除以二,将中间位置的左边重新看为数组,将数组一分为二

(4)再比较right下标的数和要寻找的数的大小,重复上述步骤,直到找到或left=right

int BinarySearch(int* arr, int len, int val)
{
	int left = 0;
	int right = len / 2;
	while (right >= 1)
	{
		if (arr[right] == val)
		{
			return right;
		}
		if (arr[left] == val)
		{
			return left;
		}
		if (arr[right] > val)
		{
			right = (right + 1) / 2;
		}
		else
		{
			left = right;
			right = (left + len) / 2;
		}
	}
}

递归:

int BinarySearch0(int* arr, int left, int right, int len,int val)
{
	if (arr[right] == val)
	{
		return right;
	}
	else if (arr[left] == val)
	{
		return left;
	}
	else if (arr[right] > val)
	{
		BinarySearch0(arr, left, (left + right) / 2,len, val);
	}
	else if (arr[right] 
  • 时间复杂度

    • 平均情况:O (log n)
    • 最坏情况:O (log n)
    • 最好情况:O (1)(目标元素恰好在中间位置)
  • 空间复杂度

    • 迭代实现:O (1)(仅需常数级额外空间)
    • 递归实现:O (log n)(递归调用栈的深度)

归并排序:

将数组分为n个归并段,分别将两个归并段内的数据排列有序,再将归并段范围扩大排列有序,直到只存在一个归并段

非递归:

void Merge(int* arr, int len, int gap)
{
	int left1 = 0;
	int right1 = left1 + gap - 1;
	int left2 = right1 + 1;
	int right2 = left2 + gap - 1 > len - 1 ? len - 1 : left2 + gap - 1;
	int* tmp = (int*)malloc(len * sizeof(int));
	int j = 0;
	//存在两个归并段
	while (left2 len - 1 ? len - 1 : left2 + gap - 1;
	}
	//不存在两个归并段
	for (int i = left1; i 

递归:

void Merge0(int* arr, int left1, int right1,int left2,int right2 , int len,int gap,int* tmp,int j)
{
	//存在两个归并段
	if(left2  len - 1 ? len - 1 : left2 + gap - 1;
		Merge0(arr, left1, right1, left2, right2, len, gap, tmp, j);
	}
	//不存在两个归并段
	else
	{
		for (int i = left1; i  len - 1 ? len - 1 : left2 + i - 1;
		int j = 0;
		Merge0(arr, left1, right1, left2, right2,len, i,tmp,j);
	}
}
  • 时间复杂度

    • 平均情况:O (n log n)
    • 最坏情况:O (n log n)
    • 最好情况:O (n log n)
  • 空间复杂度:O (n)(需要额外的数组存储合并结果)

  • 稳定性:稳定(相等元素的相对位置在排序后保持不变)

堆排序:

堆排序时分为两种情况:

大堆顶和小堆顶:

大堆顶:根节点始终大于他的左孩子和右孩子的情况

小堆顶:根节点始终小于他的左孩子和右孩子的情况

(1)首先将每一个根节点和左右孩子变幻为大堆顶或小堆顶

(2)再将树的根节点和最后一个叶子节点交换位置

(3)重复上述步骤(1)(2)直至有序

void ADjust(int* arr,int begin,int len)
{
	int tmp = arr[begin];
	while (2*begin+1 tmp)
		{
			arr[begin] = arr[maxindex];
			begin = maxindex;
		}
		else
			break;
	}
	arr[begin] = tmp;
}
void HeapSort(int* arr, int len)
{
	for (int i = (len - 1 - 1) / 2; i >= 0; i--)
		ADjust(arr, i, len);
	Swap(&arr[0], &arr[len - 1]);
	len--;
	while (len > 0)
	{
		ADjust(arr, 0, len);
		Swap(&arr[0], &arr[len - 1]);
		len--;
	}
}
  • 时间复杂度

    • 平均情况:O (n log n)

    • 最坏情况:O (n log n)

    • 最好情况:O (n log n)

  • 空间复杂度:O (1)(原地排序,仅需常数级额外空间)

  • 稳定性:不稳定(堆调整过程中可能改变相等元素的相对位置)

希尔排序:

(1)将数组分为n组,且跳跃性分组例如下图,以五个跳跃为一组进行排序

(2)再将跳跃数缩小为3,进行排序

(3)直至跳跃数缩小为1,进行排序后,整个数组已经大致有序再对数组进行快排,即可得到有序数组

void Shell(int *arr, int len, int gap){
for(int i=gap; i=0; j=j-gap) {
if(arr[j] > tmp) {
arr[j+gap] = arr[j];
}
else {
break;
}
}
arr[j+gap] = tmp;
}
}
void Shell_Sort(int *arr, int len){
int gap[] = {5,3,1};//缩小增量数组
for(int i=0; i
  • 时间复杂度

    • 平均情况:取决于增量序列,通常为 O (n^1.3)

    • 最坏情况:O (n²)(当增量序列为 1,2,4,… 时)

    • 最好情况:O (n)(当增量序列选择适当时)

  • 空间复杂度:O (1)(原地排序,仅需常数级额外空间)

  • 稳定性:不稳定(不同增量轮次的插入排序可能改变相等元素的相对位置)

文章来源于互联网:数据结构—排序算法(2)

相关推荐: AIGC(生成式AI)试用 24 — 跟着清华教程学习 – 普通人如何抓住DeepSeek红利

目标:继续学习 个人理解: – 扩展生存的空间:广度和深度 – 更多的奇思妙想得到更快的、更充分的、更有逻辑的验证 – “如何提问”仍是最关建的问题:学会问问题和挑选答案     > 学会发现问题、有解决问题的意愿、对问题有明确的期望     > …

赞(0)
未经允许不得转载:5bei.cn大模型教程网 » 数据结构---排序算法(2)
分享到: 更多 (0)

AI大模型,我们的未来

小欢软考联系我们