数据结构基础10(排序算法)

1.冒泡

void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

//冒泡   时间复杂度:O(n²)空间复杂度:O(1) 因为没有申请空间  稳定性:稳定
void BubbleSort(int* arr, int len)
{
	for (int i = 0; i < len - 1; ++i)
	{
		for (int j = 0; j < len - 1 - i; ++j)
		{
			if (arr[j] > arr[j + 1])
			{
				Swap(&arr[j], &arr[j + 1]);
			}
		}
	}
}

2.选择

//选择排序  时间复杂度:O(n²)空间复杂度:O(1)   稳定性:不稳定
void SelectSort(int* arr, int len)
{
	for (int i = 0; i < len - 1; ++i)
	{
		int min_index = i;
		for (int j = i; j < len; ++j)
		{
			if (arr[min_index] > arr[j])
			{
				min_index = j;
			}
		}
		Swap(&arr[i], &arr[min_index]);
	}
}

3.直接插入

//直接插入排序  时间复杂度:O(n²)空间复杂度:O(1)   稳定性:稳定
//对于已经有序的数据系列:时间复杂度为O(n)
void InsertSort(int* arr, int len)
{
	for (int i = 1; i < len; ++i)
	{
		int tmp = arr[i];
		int j;
		for (j = i - 1; j >= 0; --j)
		{
			if (arr[j] <= tmp)
			{
//				arr[j + 1] = tmp;
				break;
			}	
			arr[j + 1] = arr[j];
		}
		arr[j + 1] = tmp;
	}
}

4.希尔排序

//希尔排序:对于直接插入排序的优化  时间复杂度:O(n^1.3)...O(n^1.5)  空间复杂度:O(1) 稳定性:不稳定
void Shell(int* arr, int len, int d)
{
	for (int i = d; i < len; ++i)
	{
		int tmp = arr[i];
		int j;
		for (j = i - d; j >=0;j -= d )
		{
			if (arr[j] <= tmp)
			{
				break;
			}
			else
			{
				arr[j + d] = arr[j];
			}
		}
		arr[j+d] = tmp;
	}
}

void ShellSort(int* arr, int len)
{
	//增量序列中的值必须都是互质的(最大公约数为),最后一个必须为1 
	int d[] = { 5,3,1 };
	for (int i = 0; i < sizeof(d) / sizeof(0); ++i)
	{
		Shell(arr, len, d[i]);
	}
}

5.堆排序


//堆排序  时间复杂度:O(nlogn)  空间复杂度:O(1) 稳定性:不稳定

//构建一个大根堆
void OneAdjust(int* arr, int len, int root)
{
	int i = root;
	int j = 2 * i + 1;//j是root的左孩子下标
	int tmp = arr[root];
	while (j < len)
	{
		if (j + 1 < len && arr[j] < arr[j + 1])  //如果有右孩子  右孩子>左孩子
		{
			j = j + 1;
		}//if判断完后,可以知道j是较大孩子的下标
		if (arr[j] < tmp)
		{
			break;
		}
		arr[i] = arr[j];
		i = j;
		j = 2 * i + 1;    //再去看后面的子树
	}
	arr[i] = tmp;
}

//创建堆
void CreateHeap(int* arr, int len)
{
	//root为最后一棵子树的根节点、
	int root = (len - 2) / 2;
	for (; root >= 0; root--)
	{
		OneAdjust(arr, len, root);
	}
}

void HeapSort(int* arr, int len)
{
	CreateHeap(arr, len);

	for (int i = 0; i < len-1; ++i)   //剩最后一个数据 没必要进行比较 
	{
		Swap(&arr[0], &arr[len - 1 - i]);
		OneAdjust(arr, len - i - 1, 0);  //如果不减一最后一个数字就会包含进去
	}
}

6.快速排序

1.思想及实现

在这里插入图片描述

//快速排序
int OneQuick(int* arr, int start, int end)
{
	SelectPivotMedianOfThree(arr, start, end);

	int tmp = arr[start];
	while (start < end)  //整个寻找过程
	{
//一次循环 如果没有start<end  有可能在小while中越界,而外侧循环来不及判断
		while (start < end && arr[end] >= tmp) 
		{
			end--;
		}
		arr[start] = arr[end];
		while (start < end && arr[start] <= tmp)
		{
			start++;
		}
		arr[end] = arr[start];
	}
	arr[start] = tmp;
	return start;   //返回当前基准数据所在的数据
}

//递归方式
// O(nlogn)   空间:O(logn)  递归调用函数开辟栈空间  不稳定
void Quick(int* arr, int start, int end)
{
	if (end - start < 10)
	{
		InsertSort(arr + start, end - start+1);
		return;
	}

	int mod = OneQuick(arr, start, end);  //mod将数据分为两部分 n
	//左   start...mod-1
	if (mod - start > 1)   //logn
	{
		Quick(arr, start, mod - 1);
	}
	//右   mod+1...end
	if (end - mod  > 1)
	{
		Quick(arr, mod + 1, end);
	}
}

void QuickSort(int* arr, int len)
{
	//Quick(arr, 0, len - 1);
	QuickNoR(arr, 0, len - 1);
}

2.非递归实现

在这里插入图片描述

//快速排序
int OneQuick(int* arr, int start, int end)
{
	SelectPivotMedianOfThree(arr, start, end);

	int tmp = arr[start];
	while (start < end)  //整个寻找过程
	{
//一次循环 如果没有start<end  有可能在小while中越界,而外侧循环来不及判断
		while (start < end && arr[end] >= tmp) 
		{
			end--;
		}
		arr[start] = arr[end];
		while (start < end && arr[start] <= tmp)
		{
			start++;
		}
		arr[end] = arr[start];
	}
	arr[start] = tmp;
	return start;   //返回当前基准数据所在的数据
}


//非递归方式
void QuickNoR(int* arr, int start, int end)
{
	SqStack st;
	InitStack(&st);
	PushStack(&st, start);
	PushStack(&st, end);
	while (!EmptyStack(&st))
	{
		int right = 0;
		PopStack(&st, &right);
		int left = 0;
		PopStack(&st, &left);
		int mod = OneQuick(arr, left, right);
		if (mod - left > 1)
		{
			PushStack(&st, left);
			PushStack(&st, mod-1);
		}
		if (right - mod > 1)
		{
			PushStack(&st, mod + 1);
			PushStack(&st, right);
		}
	}
}

void QuickSort(int* arr, int len)
{
	//Quick(arr, 0, len - 1);
	QuickNoR(arr, 0, len - 1);
}

3.优化快排

在这里插入图片描述

void SelectPivotMedianOfThree(int* arr, int start, int end)
{
	int mod = (end - start) / 2 + start;

	if (arr[mod] > arr[end])
	{
		Swap(&arr[end], &arr[mod]);
	}
	if (arr[start] > arr[end])
	{
		Swap(&arr[start], &arr[end]);
	}
	if (arr[start] < arr[mod])   //把中位数放在start
	{
		Swap(&arr[start], &arr[mod]);
	}
}

4.附上:链接栈文件的方法

在这里插入图片描述

7.二路归并排序


8.基数排序

//基数排序-->多关键字的排序
//时间复杂度:O(d*n)  空间复杂度:O(n)  稳定

int GetMaxDigits(int* arr, int len)
{
	int maxValue = arr[0];
	for (int i = 0; i < len; ++i)
	{
		if (arr[i] > maxValue)
		{
			maxValue = arr[i];
		}
	}
	//计算最大的位数   12345
	int digits = 0;
	while (maxValue)
	{
		digits++;
		maxValue /= 10;
	}
	return digits;
}

int GetDigitsValue(int value, int digits)
{
	while (digits)
	{
		value /= 10;
		digits--;
	}
	return value % 10;
}

void RadixSort(int* arr, int len)
{
	//1.获取所有数据中最大的关键字的个数
	int maxDigits = GetMaxDigits(arr, len);
	//2.申请关键字范围个数的队列   0---9  十个队列 每个队列的长度就是所有数据个数len
	SqQueue que[10];
	for (int i = 0; i < 10; ++i)
	{
		InitQueue(&que[i], len + 1);
	}

	//3.循环根据各关键字将数据依次存储到对应的序列中,最后再将队列依次输出
	for (int i = 0; i < maxDigits; ++i)
	{
		//3.1将所有的数据依次存储在对应队列中
		for (int j = 0; i < len; ++j)
		{
			int digValue = GetDigitsValue(arr[j], i);
			PushQueue(&que[digValue], arr[j]);
		}
		//3.2将队列中的所有数据依次输出到arr中
		int index = 0;
		for (int k = 0; k < 10; ++k)
		{
			while (!EmptyQueue(&que[k]))
			{
				PopQueue(&que[k], &arr[index]);
				index++;
			}
		}
	}
	//释放所有的队列
	for (int i = 0; i < 10; ++i)
	{
		DestoryQueue(&que[i]);
	}
}

9.主函数

int main()
{
	srand((unsigned int)(time(NULL) * time(NULL)));
	int arr[LEN];
	for(int i = 0; i < LEN; ++i)
	{
		arr[i] = rand() % 100;
		printf("%d ", arr[i]);
	}
	printf("\n");

	//BubbleSort(arr, LEN);
	//SelectSort(arr, LEN);
	//InsertSort(arr, LEN);
//	HeapSort(arr, LEN);
//	ShellSort(arr, LEN);
	QuickSort(arr, LEN);
	for (int i = 0; i < LEN; ++i)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值