排序的算法

1.插入排序

步骤:

1.从第一个元素开始,只有一个元素时,该元素必定有序,所以从数组的第二个元素开始排序
2.从数组取出排好序的部分后的第一个数字tmp,和已经排好序的部分进行比较
3.将tmp从后往前依次和有序部分的数进行比较,设置一个寻找比较的指针为end,如果该tmp小于end指向的数,则将end指向的数赋值给end+1所指向的位置,end--
4.重复步骤3,直到找到已排序元素中小于tmp的数
5.如果已排序所有元素都大于tmp,则将tmp插入到下标为0的位置
6.重复步骤2~5

思路:
  在待排序的元素中,假设前n-1个元素已有序,现将第n个元素插入到前面已经排好的序列中,使得前n个元素有序。按照此法对所有元素进行插入,直到整个序列有序。
  但我们并不能确定待排元素中究竟哪一部分是有序的,所以我们一开始只能认为第一个元素是有序的,依次将其后面的元素插入到这个有序序列中来,直到整个序列有序为止。

代码:

#include<stdio.h>
void InsertSort(int* a, int n) {
	for (int i = 1; i < n; i++) 
	{
	int end = i-1;
	int tmp = a[i];
	while (end >= 0) 
	{
		if (tmp < a[end])//比插入的数大就向后移
		{
			a[end + 1] = a[end];
			end--;
		}
		else//比插入的数小,跳出循环
		{
			break;
		}
	}
//将tmp赋值运算放在循环外面,是因为有两种情况,一种是找到比tmp小的,break结束循环,第二种情况情况是找不到比tmp小的,退出循环,如果把赋值运算放在else,第二种情况就无法处理
	a[end + 1] = tmp;
//tmp放到比插入的数小的数的后面
}
	}
	
int main() {
	int a[] = { 7,8,2,0,3,1,7,9,4,5 };
	InsertSort(a,sizeof(a)/sizeof(a[0]));
	for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
	{
		printf("%d ", a[i]);
	}
	
}

时间复杂度:数组是逆序或者接近逆序是最坏情况,为O(N*N)
      数组是顺序或者接近顺序是最好情况,为O(N)。
空间复杂度:O(1)

2.希尔排序

步骤:
1.先选定一个小于N的整数gap作为第一增量,然后将所有距离为gap的元素分在同一组,并对每一组的元素进行直接插入排序。然后再取一个比第一增量小的整数作为第二增量,重复上述操作…
2.当增量的大小减到1时,就相当于整个序列被分到一组,进行一次直接插入排序,排序完成。

思路:
希尔排序,先将待排序列进行预排序,使待排序列接近有序,然后再对该序列进行一次插入排序,此时插入排序的时间复杂度为O(N),

代码如下:

void ShellSort(int* a, 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 = a[i+gap];
	while (end >= 0)
	{
		if (tmp < a[end])
		{
			a[end + gap] = a[end];
			end -= gap;
		}
		else
		{
			break;
		}
	}
	a[end + gap] = tmp;
	}
	}
	
}

时间复杂度平均:O(N^1.3)
空间复杂度:O(1)

3.冒泡排序

思路:
左边大于右边交换一次,依次遍历整个数组,一趟排下来最大的在右边,将最大的数排除在外,再重复这个过程,直到待排序的数为1或者有序结束。

代码如下

void BubbleSort(int* a, int n) {
	
	for (int j = n - 1; j > 0; j--)
	{
		int flag = 0;
	for (int i = 0; i < j; i++)
	{
		if (a[i] > a[i + 1])
		{
			int tmp = a[i];
			a[i] = a[i + 1];
			a[i + 1] = tmp;
			flag = 1;
		}
		if (flag == 0)
		{
			break;
		}
	}
	}
}

时间复杂度:最坏情况:O(N^2)
      最好情况:O(N)
空间复杂度:O(1)

4.选择排序

思路:
每次从待排序列中选出一个最大值,然后放在序列的尾部位置,直到全部待排数据排完即可。
 

void SelectSort(int* a, int n)
{
	int right = n-1;
	
	while (right)
	{
		int cur = right-1;
		int max = a[right];
		while (cur >= 0) 
		{
			if (max < a[cur])
			{
				int tmp = a[cur];
				a[cur] = max;
				max = tmp;
			}
			cur--;
		}
		a[right] = max;
		right--;
	}
}

时间复杂度:最坏情况:O(N^2)
      最好情况:O(N^2)
空间复杂度:O(1)

5.堆排序

//降序
void HeapSort(int* a, int n)
{
	//建小堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}
	int end = n - 1;
	//把最小的换到最后一个位置,不把最后一个数看作堆里的
	//每次选出剩下数中最小的
	//从后往前放
	while (end > 0)
	{
		int tem = a[end];
		a[end] = a[0];
		a[0] = tem;
		//选出次小的数
		AdjustDown(a, end, 0);
		--end;
	}
}

6.快速排序

5.1 hoare版本(左右指针法)

5.1 hoare版本(左右指针法)
思路:
1、选出一个key,一般是最左边或是最右边的。
2、定义一个begin和一个end,begin从左向右走,end从右向左走。(需要注意的是:若选择最左边的数据作为key,则需要end先走;若选择最右边的数据作为key,则需要bengin先走)。
3、在走的过程中,若end遇到小于key的数,则停下,begin开始走,直到begin遇到一个大于key的数时,将begin和right的内容交换,end再次开始走,如此进行下去,直到begin和end最终相遇,此时将相遇点的内容与key交换即可。(选取最左边的值作为key)
4.此时key的左边都是小于key的数,key的右边都是大于key的数
5.将key的左序列和右序列再次进行这种单趟排序,如此反复操作下去,直到左右序列只有一个数据,或是左右序列不存在时,便停止操作,此时此部分已有序

代码:

int PastSort(int* a, int left, int right) {
Max(&a[left], &a[right], &a[(left + right) / 2]);
	int keyi = left;
	while (left < right)
	{
		
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[keyi], &a[right]);
	return right;
}
QuickSort(int* a, int begin, int end) {
	if (begin >= end) {
		return;
	}

	int keyi = PastSort(a, begin, end);
	QuickSort(a, begin, keyi-1);
	QuickSort(a, keyi+1, end);
}

时间复杂度:n*logn

5.2 挖坑法

思路:
挖坑法思路与hoare版本(左右指针法)思路类似
1.选出一个数据(一般是最左边或是最右边的)存放在key变量中,在该数据位置形成一个坑
2、还是定义一个L和一个R,L从左向右走,R从右向左走。(若在最左边挖坑,则需要R先走;若在最右边挖坑,则需要L先走)

后面的思路与hoare版本(左右指针法)思路类似

代码:

int PastSort(int* a, int left, int right) {
Max(&a[left], &a[right], &a[(left + right) / 2]);
	int key = a[left];
	int hole = left;
	while (left < right)
	{
		
		while (left < right && a[right] >= key)
		{
			right--;
		}
		a[hole] = a[right];
		hole = right;
		while (left < right && a[left] <= key)
		{
			left++;
		}
		a[hole] = a[left];
		hole = left;
	}
	a[hole] = key;
	return hole;
}
QuickSort(int* a, int begin, int end) {
	if (begin >= end) {
		return;
	}

	int keyi = PastSort(a, begin, end);
	QuickSort(a, begin, keyi-1);
	QuickSort(a, keyi+1, end);
}

5.3 前后指针法

思路:
1、选出一个key,一般是最左边或是最右边的。
2、起始时,prev指针指向序列开头,cur指针指向prev+1。
3、若cur指向的内容小于key,则prev先向后移动一位,然后交换prev和cur指针指向的内容,然后cur指针++;若cur指向的内容大于key,则cur指针直接++。如此进行下去,直到cur到达end位置,此时将key和++prev指针指向的内容交换即可。

经过一次单趟排序,最终也能使得key左边的数据全部都小于key,key右边的数据全部都大于key。

然后也还是将key的左序列和右序列再次进行这种单趟排序,如此反复操作下去,直到左右序列只有一个数据,或是左右序列不存在时,便停止操作

代码:

void Swap(int* a, int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
int PastSort(int* a, int left, int right) {
	int prev = left;
	int cur = left + 1;
	int keyi = left;
	while (cur <= right)
	{
		
		if (a[cur] < a[keyi] && prev++ != cur)
		{
			Swap(&a[prev], &a[cur]);
		}
		cur++;
		
		
	}
	Swap(&a[keyi], &a[prev]);
	keyi  = prev;
	return keyi;

}
void QuickSort(int* a, int begin, int end) {
	if (begin >= end)
	{
		return;
	}
	int keyi = PastSort(a, begin, end);
	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi+1, end);
}

5.4 非递归

void QuickSort(int* a, int begin, int end) {
	Stack s;
	InitStack(&s);
	
	StackPush(&s,  end);
	StackPush(&s, begin);
	while (!StackEmpty(&s))
	{
		int left = StackTop(&s);
		StackPop(&s);
		int right = StackTop(&s);
		StackPop(&s);
		if (left < right)
		{
		int keyi = PastSort(a, left, right);
		StackPush(&s, right);
		StackPush(&s, keyi+1);
		StackPush(&s, keyi-1);
		StackPush(&s, left);
		
		}
		

	}
}

  • 12
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值