排序算法

排序算法:

**排序算法的稳定性:**
    在待排序的数据中,如果有值相同的数据,在排序的过程中如果不会改变它们的相对顺序,则认为该排序算法为稳定的。
    4 2 1 0 9 4 3 8 7
    a         b
    0 1 2 3 4 4 7 8 9
            a b【稳定的】
            b a【不稳定的】
    
**冒泡:**
    对数据左右进行比较,把最大的交换到最后,特点是该算法对数据的有序性敏感,在排序的过程中发现有序可以立即停止,如果待排序的数据基本有序,则冒泡排序的效率是非常高的。
    时间复杂度:平均:O(n^2) 最优:O(n)
    稳定性: 稳定的

**选择:**
    假定最开始的位置是最小值的下标并记录该下标为min,然后与后面的数据进行比较,如果有比min位置的数据小的,则更新min为更小的数据的下标,最后如果最后min的值发生了变化,则交换min位置的数据与最开始位置的数据,虽然时间复杂度较高,但是数据交换的次数比较少,因此实际运行的速度并不慢
    选择排序是冒泡排序的一个变种,但是对数据的有序性不敏感,数据基本有序时冒泡快,数据较为混乱时选择快
    时间复杂度:O(n^2)
    稳定性:不稳定的  10 10 1

**插入:**
    把数据看成两部分,一部分是有序的,剩余的数据逐个插入进去,当数据全部插入完成后,整个数据就是有序的。
    适合对已排序好的数据,新增数据并排序
    时间复杂度:zO(n^2)
    稳定性:稳定的

**快速:**
83 86 77 15 [93] 35 86 92 49 21 
83 86 77 15 21 35 86 92 49 93
83 86 77 15 [21] 35 86 92 49 
15 21 77 86 83 35 86 92 49 93 
77 86 83 [35] 86 92 49 
15 21 35 86 83 77 86 92 49 93 
86 83 [77] 86 92 49 
15 21 35 49 77 86 86 92 83 93 
86 [86] 92 83 
15 21 35 49 77 86 83 86 92 93 
[86] 83 
15 21 35 49 77 83 86 86 92 93
    找到一个标杆,一方面从左边找比标杆值大的数据,找到后放在标杆的右边,另一方面从右边找比标杆值小的数据,找到后放在标杆的左边,最终标杆左边的数据都比它小,右边的数据都比它大,这样整体有序,然后再按照同样的方式排序标杆左右两边的的数据。
    它的综合性能高,因此叫快速排序,笔试考的最多的是快排  
    时间复杂度:O(nlogn)
    稳定性:不稳定

**归并:**
    先把一组数据拆分成单独的个体,然后以从小到大的顺序进行合并,由于需要使用额外的内存空间因此避免了数据的交换的耗时,也是一种典型的以空间换时间的算法
    时间复杂度 O(nlogn)
    稳定性:稳定的

**堆:**
    把数据当做完全二叉树,然后在树中调整为大根树,然后把根节点交换到末尾,然后数量--,接下去继续调整为大根树,直到节点数量为1时结束,结束后该数据就是有序的。
    时间复杂度 O(nlogn)
    稳定性:不稳定的

代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define swap(a,b) {typeof(a) t=a;a=b;b=t;}
#define LEN 10

//	冒泡排序
void bubble_sort(int* arr,size_t len)
{
	// 标志位判断是否排序完成
	bool flag = true;	
	for(int i=len-1; i>0 && flag; i--)
	{
		flag = false;
		for(int j=0; j<i; j++)
		{
			//printf("===========\n");
			if(arr[j] > arr[j+1])
			{
				swap(arr[j],arr[j+1]);
				flag = true;
			}
		}
	}
}

//	选择排序
void select_sort(int* arr,size_t len)
{
	for(int i=0; i<len-1; i++)
	{
		int min = i;
		for(int j=i+1; j<len; j++)
		{
			if(arr[j] < arr[min])	min = j;
		}
		if(min != i) swap(arr[min],arr[i]);
	}
}

//	插入排序
void insert_sort(int* arr,size_t len)
{
	for(int i=1,j=0; i<len; i++)
	{
		int val = arr[i];
		for(j=i; j>0 && arr[j-1] > val;j--)
		{
			arr[j] = arr[j-1];	
		}
		if(j != i) arr[j] = val;
	}
}

void _quick_sort(int* arr,int left,int right)
{
	if(left >= right) return;

	//	计算标杆下标位置
	int pi = (left+right)/2;
	//	备份标杆的值
	int pv = arr[pi];
	//	备份左右标杆的下标位置
	int l = left, r = right;
	//当左右标杆相遇结束
	while(l < r)
	{
		//	在标杆左边找比pv大的数据
		while(l<pi && arr[l]<=pv) l++;
		if(l<pi) 
		{
			//找到后
			arr[pi] = arr[l];
			pi = l;
		}

		// 在标杆右边找比pv小的数据
		while(r>pi && arr[r]>=pv) r--;
		if(r>pi)
		{
			//找到了
			arr[pi] = arr[r];
			pi = r;
		}
	}
	// 还原标杆
	arr[pi] = pv;
	//show_arr(arr,LEN);
	//如果左边数据不少2个,左边继续快排
	if(pi-left>1) _quick_sort(arr,left,pi-1);
	if(right-pi>1)_quick_sort(arr,pi+1,right);
}

//	快速
void quick_sort(int* arr,size_t len)
{
	_quick_sort(arr,0,len-1);
}

//	合并
void merge(int* arr,int* tmp,int l,int p,int r)
{
	//l是左部分最左 p是左部分最右 p+1是右部分最左 r是右部分最右
	//认为合并前 左右部分各自是有序的

	if(arr[p] <= arr[p+1]) return;

	int i = l, j = p+1, k = l;
	while(i<=p && j<=r)
	{
		// 从左右部分的最左开始,比较谁小谁先放如tmp
		if(arr[i] < arr[j])
			tmp[k++] = arr[i++];
		else
			tmp[k++] = arr[j++];
	}
	// 任意一部分放入结束后,把另一部分剩余的放入tmp末尾
	while(i<=p) tmp[k++] = arr[i++];
	while(j<=r) tmp[k++] = arr[j++];
	//	把tmp合并排序好后的数据重新赋值给arr对应的位置
	while(l<=r) arr[l] = tmp[l++];
}

//	拆分
void _merge_sort(int* arr,int* tmp,int l,int r)
{
	if(l >= r) return;
	int p = (l+r)/2;
	_merge_sort(arr,tmp,l,p);
	_merge_sort(arr,tmp,p+1,r);
	//合并
	merge(arr,tmp,l,p,r);
}

//	归并
void merge_sort(int* arr,size_t len)
{
	int* tmp = malloc(sizeof(int)*len);
	_merge_sort(arr,tmp,0,len-1);
	free(tmp);
}

//	构建堆结构
void create_heap(int* arr,int root,size_t len)
{
	// root是堆顶的下标,不是编号
	if(root >= len) return;

	//	left right是左右孩子下标
	int left = root*2+1, right = root*2+2;
	create_heap(arr,left,len);
	create_heap(arr,right,len);
	if(right<len && arr[right] >arr[left])
		swap(arr[right],arr[left]);
	if(left<len && arr[left]>arr[root])
		swap(arr[left],arr[root]);
}

//	堆排序
void heap_sort(int* arr,size_t len)
{
	//调整为大根树
	create_heap(arr,0,len);
	
	//交换堆顶与末尾,然后数量--,并剩余重新调整为大根树
	for(int i=len-1; i>=0; i--)
	{
		swap(arr[0],arr[i]);
		create_heap(arr,0,i);
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值