代码世界之伟大的数据结构:排序

概叙

排序算法总览

相关知识点:

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。

  • 不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。

  • 时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。

  • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数

2.它们之间的性能比较:
在这里插入图片描述
当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序``堆排序 归并排序

排序有内部排序外部排序,内部排序是数据记录在内存中进行排序,而外部排序是排序的数据很大,一次不能容纳全部的排序记录,而排序过程中需要访问外存

八大排序就是内部排序。

插入排序

简单插入排序

算法描述:
  • 从第一个元素开始划分出一个有序的序列
  • 依次取出下一个元素,在已经排序的元素序列中从后向前扫描
  • 如果已排序元素大于新元素,该元素移到下一个我位置
  • 重复步骤3,直到找到新元素所在位置
  • 重复2,5步骤
    在这里插入图片描述
c语言实现:
 #直接插入排序
 
#include<stdio.h>
#include<string.h>
void InsertionSort(int* arr,int len)
{
	int i ,j;
	for (i = 1;i <= len;i++)
	{
		j = i;
		while (j--)
		{
			if (arr[j - 1] > arr[j])
			{
				int temp = arr[j - 1];
				arr[j - 1] = arr[j];
				arr[j] = temp;
			}
			else
			{
				break;//小于退出while循环提高效率
			}
		}
	}
}
int main()
{
	int arr[] = {8,3,9,5,6,7,1,4,0,2};
	int i = 0;
	int len = sizeof(arr) / sizeof(arr[0]);
	InsertionSort(arr,len);
	for (i = 0;i < (sizeof(arr) / sizeof(arr[0]));i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}
 

希尔排序

算法描述:

又称缩小增量排序

  • 选择一个增量序列
  • 每趟排序,根据对应的增量t,进行两两数据比较,将小的放在前,大的放在后
  • 重复第二步,直到增量已用尽

在这里插入图片描述
简单选择排序的基本思想:比较+交换

c语言实现:
#include<stdio.h>
#include<stdlib.h>
void swap(int* L, int* R)
{
	int temp = *L;
	*L = *R;
	*R = temp;
}
void ShellSort(int* arr, int len)
{
	for (int gap = (len / 2); gap > 0;gap /= 2)//设置gap起始间距为长度的一半
	{
		//以gap为间距组从一个组,每次对这个组进行直接插入排序
		for (int i = gap; i < len;i++)
			//以gap位置为起始,找到每一个元素以gap间隔为组向前进行直接插入排序
		{
			int j = i;
			while ((arr[j]< arr[j - gap]) && j - gap >= 0)
				{
					swap(&arr[j],&arr[j -gap]);
					j -= gap;//找到之前所有的成员比较并排序
				}	
		}
	}
}
 
int main()
{
	int arr[] = { 8,3,9,5,6,7,1,4,0,2 };
	int i = 0;
	int len = sizeof(arr) / sizeof(arr[0]);
	ShellSort(arr, len);
	for (i = 0;i < len;i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

交换排序

冒泡排序

算法描述:
  • 第一轮从头到尾对n个元素进行两两比较,进行调换位置
  • 需要对余下的n-1个数据进行从头到尾两两比较直到数据有序为止

在这里插入图片描述

c语言实现:
#include<stdio.h>
#include<string.h>
void bubbleSort(int* arr,int len)
{
	int i, j;
	for (i = 0;i < len - 1;i++)
	{
		for (j = 0;j < len - 1 - i;j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}
int main()
{
	int i;
	int arr[] = {6,3,8,7,5,4,1,2,0};
	int len = sizeof(arr) / sizeof(arr[0]);
	bubbleSort(arr,len);
	for (i = 0;i < (sizeof(arr) / sizeof(arr[0]));i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

快速排序

算法描述:

实例排序:

一趟排序结果:{49 38 65 97 76 13 27 49’}

二趟排序结果:{27 38 13} 49 {76 97 65 49’}

三趟排序结果:{13} 27 {38} 49 {76 97 65 49’}

四趟排序结果:13 27 38 49 {49’ 65} 76 {97}

  • 定义low和high指向头尾两个关键数据

  • 将low所指数据与其后面数据进行比较,如果比其小就把它放在该数据的前面

  • 将high所指数据与其后面数据进行比较,如果比其大就把它放在该数据的后面

  • 当low和high指针所指数据重叠时,将数据分为两组,重新设置头尾数据为low和high,重复上述操作,直至数据有序

在这里插入图片描述

c语言实现:
#include<stdio.h>
#include<string.h>
#include<assert.h>
 
void QuickSort(int* arr,int left, int right)
{
	int i = left; 
	int j = right;
	int temp = arr[i];
 
	if (i >= j)
		return;
 
	while (i != j)
	{
		while (arr[j] >= temp && i < j)
		{
			j--;
		}
		if (i < j)
		{
			arr[i] = arr[j];
		}
		while (arr[i] <= temp && i < j)
		{
			i++;
		}
		if ( i < j)
		{
			arr[j] = arr[i];
		}
	}
	arr[i] = temp;
	QuickSort(arr,left,i - 1);
	QuickSort(arr, i + 1, right);
}
 
int main()
{
	int arr[] = {8,3,9,5,6,7,1,4,0,2};
	int i = 0;
	int len = sizeof(arr) / sizeof(arr[0]);
	QuickSort(arr,0,len - 1);
	for (i = 0;i < len ;i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

选择排序

简单选择排序

算法描述:
  • 在第一个位置开始从数组找到最小的数据

  • 往下一个位置开始找到数组中最小的数据

  • 重复第二步,直到数组有序为止

在这里插入图片描述

c语言实现:
#include<stdio.h>
#include<string.h>
void SelectionSort(int* arr, int len)
{
	int min;//保存当前最小数字下标
	for (int i = 0;i < len - 1;i++)
	{
		min = i;
		for (int j = i + 1;j < len; j++)
		{
			if (arr[min] > arr[j])
			{
				min = j;
			}
		}
		int temp = arr[min];
		arr[min] = arr[i];
		arr[i] = temp;
	}
 
	
}
int main()
{
	int arr[] = {8,3,9,5,6,7,1,4,0,2};
	int i = 0;
	int len = sizeof(arr) / sizeof(arr[0]);
	SelectionSort(arr,len);
	for (i = 0;i < len ;i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

堆排序

算法描述:

堆就是用数组实现的二叉树,所以没有父指针或字指针

堆分为两种:最大堆最小堆

两者区别:

节点的值比每一个子节点的值都要大

节点的值比每一个子节点的值都要小

鉴于最大堆和最小堆是对称关系,理解其中一种即可。所以接下来我们为你们说明一下最大堆的排序

最大堆进行升序排序的思想:
1.
初始化堆:将数列a[1…n]构成最大堆

交换数据:将a[1]和a[n] 交换,使a[n]是a[1…n]中的最大值;然后将a[1…n-1]重新调整为最大堆。 接着,将a[1]和a[n-1]交换,使a[n-1]是a[1…n-1]中的最大值;然后将a[1…n-2]重新调整为最大值。 依次类推,直到整个数列都是有序的。

c语言实现:
#include<stdio.h>
#include<string.h>
#include<assert.h>
void AdjustHead(int *arr, int parent, int len)
{//大堆
	assert(arr);
	int child = parent * 2 + 1;
	while (child < len)
	{
		if (arr[child] < arr[child + 1] && child + 1 < len)
		{
			child += 1;//左子树小于右子树交且合法时交换
		}
		if (arr[child] > arr[parent])
		{//将大值交给父亲节点
			int temp = arr[child];
			arr[child] = arr[parent];
			arr[parent] = temp;
			//复位,再次判断,防止左右孩子都大于双亲
			parent = child;
			child = parent * 2 + 1;
		}
		else
			return;//不满足退出
	}
}
void HeapSort(int* arr, int len)
{
	//建堆
	int root = (len - 2) >> 1;//找到最后一个非叶子节点
	for (root;root >= 0;--root)
	{
		AdjustHead(arr, root, len);
	}
	//排序
	int end = len - 1;
	while (end)
	{
		int temp = arr[0];
		arr[0] = arr[end];
		arr[end] = temp;
		//循环排序每一个元素
		AdjustHead(arr,0,end);
		end--;
	}
}
int main()
{
	int arr[] = {8,3,9,5,6,7,1,4,0,2};
	int i = 0;
	int len = sizeof(arr) / sizeof(arr[0]);
	HeapSort(arr,len);
	for (i = 0;i < len ;i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

归并排序

归并排序

算法描述:
  • 将长度为n的输入序列分为长度为n/2的子序列
  • 对两个子序列分别采用归并排序
  • 将两个排序号的子序列合并成一个最终的排序序列

在这里插入图片描述

c语言实现:

#include<stdio.h>
#include<string.h>
#include<assert.h>
//合并
void Merge(int* arr, int low, int mid, int high)
{
	int i = low;//第一组下标
	int j = mid + 1;//第二组下标
	int k = 0;
	int arr2[100] = {0};//临时排序存放序列
//循环判断arr[i]和arr[j]的值,谁小谁放在arr2中
	while (i <= mid && j <= high)
	{
		if (arr[i] <= arr[j])
		{
			arr2[k] = arr[i];
			i++;
			k++;
		}
		else
		{
			arr2[k] = arr[j];
			j++;
			k++;
		}
	}
	//当至少一组放完后,剩下的全部按顺序放入arr2(已经有序的数组)
	//最后一组元素可能不过正常数量
	    while (i <= mid)
		{
			arr2[k] = arr[i];
			i++;
			k++;
		}
		while (j <= high)
		{
			arr2[k] = arr[j];
			j++;
			k++;
		}
		//将arr2中的序列复制到arr中
		for (k = 0, i = low;i <= high;i++, k++)
		{
			arr[i] = arr2[k];
		}
	
}
 
void MergeSort(int *arr, int len)
{
//间隔增加(gap就是一组几个元素)
	for( int gap = 1;gap < len;gap = (gap * 2) )
	{
		int i = 0;
		//从间隔gap开始排序
		for (i = 0;i + 2*gap - 1 < len;i = i + 2*gap)
		{
			Merge(arr, i , i + gap - 1 , i + 2*gap - 1 );
		}
		//当gap大于len的一半时,排序for无法排序的两个子组
		if (i + gap - 1 < len) 
		{
			Merge(arr, i, i + gap - 1, len - 1);
		}
	}
}
 
 
int main()
{
	int arr[] = {8,3,9,5,6,7,1,4,0,2};
	int i = 0;
	int len = sizeof(arr) / sizeof(arr[0]);
	MergeSort(arr,len );
	for (i = 0;i < len;i++)
	{
		printf("%d ", arr[i]);
	}
	system("pause");
	return 0;
}

 

更多内容请看个人博客:https://deng123-dev.github.io/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值