【排序算法总结】----对比常见排序算法复杂度,稳定性分析,及主要代码

学习了一些常见的排序算法,我在这里对它们进行一个梳理,我们以升序为例子。
常见排序算法主要有:直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序,计数排序。
稳定性:算法在实现的过程中是否会改变相同元素的相对位置,不改变则稳定。

1.直接插入排序

  • 主要代码
void InsertSort(int* arr, int n)
{
	for (int i = 0; i < n-1; i++)
	{
		int end = i;
		int tmp = arr[end + 1];//超过N就越界了,所以是N-1。
		while (end >= 0 && arr[end] > tmp)
		{
			arr[end + 1] = arr[end];
			--end;
		}
		arr[end + 1] = tmp;
	}
}
  • 空间复杂度:O(1),没有开辟新空间。
  • 时间复杂度
    最好情况:与目标顺序相同,仅仅需要O(n)
    最坏情况:与目标顺序逆序,需要O(n2)
    平均时间复杂度:O(n2)
  • 稳定性:稳定,数据相同时,通过arr[end+1]= tmp,数据的相对顺序不变.

2.希尔排序

  • 主要代码
void ShellSort(int* arr, int n)
{
	int gap = n ;
	while (gap>1)
	{
		gap = (gap / 3) + 1;
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = arr[end + gap];
			while (end >= 0 && arr[end] > tmp)
			{
				arr[end + gap] = arr[end];
				end = end - gap;
			}
			arr[end + gap] = tmp;
		}
	}
}
  • 空间复杂度:O(1),没有开辟新空间。
  • 时间复杂度
    平均时间复杂度: O(N1.3—N2
  • 稳定性:不稳定,调整时相同数据的相对位置会改变。

3.直接选择

  • 主要代码
void SelectSort(int* arr, int n)
{
	int left = 0;
	int right = n - 1;
	while (left < right)
	{
		int max = left;
		int min = left;
		for (int i = left; i <= right; i++)
		{
			if (arr[i] > arr[max])
				max = i;

			if (arr[i] < arr[min])
				min = i;
		}
			
		Swap(&arr[min], &arr[left]);
		if (left == max)
		{
			Swap(&arr[min], &arr[max]);
		}
		Swap(&arr[max], &arr[right]);	
		++left;
		--right;
	}
}
  • 空间复杂度:O(1),没有开辟新空间。
  • 时间复杂度
    最好情况,和最坏情况都需要O(n2)
    平均时间复杂度: O(N2
  • 稳定性:不稳定,相同数据相对位置会改变,在前面的数据会被交换都末尾。(一次选出两个数,不稳定,一次选一个数稳定,和实现的方法有关系)

4.堆排序

  • 主要代码
void AdjustDown(int* arr, int root, int n)
{
	int parent = root;
	int child = 2 * parent + 1;
	while (child<n)
	{
		if (child + 1 < n && arr[child] < arr[child + 1])
		{
			++child;
		}
		if (arr[parent] < arr[child])
		{
			Swap(&arr[parent], &arr[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
	
}

void HeapSort(int* arr, int n)
{
	for (int i = (n-2)/2; i>=0; --i)
	{
		AdjustDown(arr, i, n);
	}
	int end = n-1;
	while (end)
	{
		
		Swap(&arr[0], &arr[end]);
		--end;
		AdjustDown(arr, 0, end);
		
	}
}
  • 空间复杂度:O(1),没有开辟新空间。
  • 时间复杂度
    最好情况:与目标顺序相同,需要O(nlogn),
    最坏情况:与目标顺序逆序,需要O(nlogn)
    平均时间复杂度: O(nlogn)
  • 稳定性:不稳定,同层相同值的数据,会根据parent的情况,随机到堆顶,所以相对位置是会改变的。

5.冒泡排序

  • 主要代码
void  BubbleSort(int* arr, int len) 
{
	for (int i = 0; i <= len - 1; i++)
	{
		int flag = 0;
		for (int j = 1; j <= len - i - 1; j++)
		{
			
			if (arr[j - 1] > arr[j])
			{
				flag = 1;
				int tmp = arr[j - 1];
				arr[j - 1] = arr[j];
				arr[j] = tmp;
			}
		}
		if (flag == 0)
		{
			break;
		}
	}
}
  • 空间复杂度:O(1),没有开辟新空间。
  • 时间复杂度
    最好情况:与目标顺序相同,需要O(n),
    最坏情况:与目标顺序逆序,需要O(n2)
    平均时间复杂度: O(n2)
  • 稳定性:稳定

6.快速排序

  • 主要代码
int _QuickSort(int* arr, int begin, int end)
{
	int key = arr[end];
	int index = end;
	while (begin < end)
	{
		while (begin < end)
		{
			if (arr[begin] > key)
			{
				break;
			}
			++begin;
		}

		while (begin < end)
		{
			if (arr[end] <key)
			{
				break;
			}
			--end;
		}
		Swap(&arr[begin], &arr[end]);
	}
	Swap(&arr[end], &arr[index]);
	return end;
}

void  QuickSort(int* arr,int left, int right ) 
{
	int begin = left;
	int end = right;
	if (begin >= end)
	{
		return;
	}
	int index = _QuickSort(arr, begin, end-1);
	QuickSort(arr, 0, index - 1);
	QuickSort(arr, index + 1, end);
}
  • 空间复杂度:O(logn–n)
  • 时间复杂度
    最好情况:Key每次都能把数组分成相对均匀的两段,需要O(nlogn),
    最坏情况:与目标顺序逆序,退化成冒泡排序,需要O(n2)
    平均时间复杂度: O(nlogn)
  • 稳定性:不稳定,交换时无法保证相同数据的相对顺序不变。

7.归并排序

    • 主要代码
void Merge(int* arr, int  begin, int end,int* tmp)
{
	if (begin >= end)
	{
		return;
	}
	int mid = (begin + end) >> 1;
	Merge(arr, begin, mid,tmp);
	Merge(arr, mid + 1, end,tmp);
	int begin1 = begin, end1 = mid;
	int begin2 = mid + 1,end2 = end;
	int index = begin;
	while (begin1 <=end1 && begin2 <= end2)
	{
		if (arr[begin1] > arr[begin2])
		{
			tmp[index++] = arr[begin2++];
		}
		else
		{
			tmp[index++] = arr[begin1++];
		}
	}
	//第二段结束了,第一段还有
	if (begin1 <= end1)
	{
		while (begin1<=end1)
		{
			tmp[index++] = arr[begin1++];
		}
	}
	//第一段结束了,第二段还有
	else
	{
		while (begin2 <= end2)
		{
			tmp[index++] = arr[begin2++];
		}
	}
	//每次都要拷贝回原数组,并且长度为为end-begin+1个
	memcpy(arr + begin, tmp + begin, sizeof(int)*(end - begin+1));
}

void MergeSort(int* arr,int n)
{
	int *tmp = (int *)malloc(sizeof(int)*n);
	Merge(arr, 0, n-1,tmp);
	free(tmp);
}

  • 空间复杂度:O(n),
  • 时间复杂度
    最好情况:逆序O(nlogn)
    最坏情况:逆序O(nlogn)
    平均时间复杂度: O(nlogn)
  • 稳定性:稳定

8.基数排序

void CountSort(int *arr,int n)
{
	int max , min = arr[0];
	max = min;
	for (int i = 0; i < n; i++)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
		if (arr[i]<=min)
		{
			min = arr[i];
		}
		
	}
	int range = max - min+1;
	int* a = (int*)malloc(sizeof(int)*range);
	for (int i = 0; i < range; i++)
	{
		a[i] = 0;
	}
	
	int count = 0;
	for (int i = 0; i < n; i++)
	{
		a[arr[i] - min ]++;
	}

	for (int i = 0; i < range; i++)
	{
		while (a[i] > 0)
		{
			arr[count] = i + min;
			count++;
			a[i]--;
		}
	}
	free(a);
}


  • 空间复杂度 O(范围)
  • 时间复杂度 O(max(N,范围))
  • 稳定性:稳定

在这里插入图片描述在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值