排序算法学习

时间复杂度为O(n²)的三种排序方法、基于比较的三种排序方法

选择排序

基本思路:从 i 到 n - 1 依次遍历,找出最值与当前位置互换

简单优化:可以同时记录最大值和最小值,两边开工

变式解决问题:最小交换次数

代码实现

void mysort(int s[], int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		int minpos = i;
		for (int j = i + 1; j < n; j++)
		{
			if (s[j] < s[minpos])
				minpos = j;
		}
		if (minpos != i)
		{
			int tmp = s[i];
			s[i] = s[minpos];
			s[minpos] = tmp;
		}
	}
}

冒泡排序

基本思路:进行不断比较

简单优化:

  1. 可以使用nflags记录是不是有交换,如果没有交换那么停止排序;
  2. 使用一个数记录最后面的交换的地方,在这个数字后面的数字无需交换

代码实现

void mysort(int s[], int n)
{
	int last = n - 1;
	int nflags = 0;
	do
	{
		nflags = 0;
		int tmp_last = 0;
		for (int i = 0; i < last; i++)//注意:循环变量在循环内部一定不能改变
		{
			
			if (s[i] > s[i + 1])
			{
				int tmp = s[i + 1];
				s[i + 1] = s[i];
				s[i] = tmp;
				nflags = 1;
				tmp_last = i ;
			}
			
		}
		last = tmp_last;
	} while (nflags);

}

插入排序(简单版本)

不断进行对比,然后插入。

三种不基于比较的排序(时间复杂度为O(n), 但是数据的变化范围要尽可能地小)

计数排序(桶排序的变种)

注意,如果是成绩等等数据范围有限的数字排列,桶排序的时间复杂度竟然是O( n )全场最低

#include <iostream>
#include <map>
using namespace std;
int a[1000];
int b[1000];
map<int, int >bucket;

void my_sort(int* s, int n)
{
	int max_num = s[0];
	int min_num = s[0];

	map<int, int >t;
	for (int i = 0; i < n; i++)
	{
		if (s[i] > max_num)
			max_num = s[i];
		if (s[i] < min_num)
			min_num = s[i];
		t[s[i]]++;
	}
	for (int i = min_num,k = 0; i <= max_num; i++)
	{
		int pos = 0;
		while (t[i]--)
			s[k++] = i;
	}
}
void print(int s[], int n)
{
	for (int i = 0; i < n; i++)
		cout << s[i] << ' ';
}
int main()
{
	
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> a[i];
	my_sort(a, n);
	print(a, n);
}

基数排序

类似于桶排序:

  1. 但是可以更好地在内存不够的情况下拓展桶排序的数目(可以设置的位数不一定是一位,还可以多次设置)
  2. 可以完成多级排序

重点是类似于队列,不同队列,从左到右,相同队列,从前到后

避坑:从优先级最后按照顺序向前排列

代码实现

#include <iostream>
#include <map>
#include <cmath>
using namespace std;
int a[1000];
int b[1000];
void jishupaixu(int *s, int n)
{
	for (int t = 0; t < 10; t++)
	{
		int a[10][1000] = { 0 };
		int pos[10] = { 0 };
		int shang = pow(10, t);
		for (int i = 0; i < n; i++)
		{
			int hs = s[i] / shang % 10;
			a[hs][(pos[hs]++)] = s[i];
		}
		for (int i = 0, p = 0; i < 10; i++)
		{
			
			for (int j = 0; j < pos[i]; j++)
			{
				s[p++] = a[i][j];
			}
		}
	}
}
void print(int s[], int n)
{
	for (int i = 0; i < n; i++)
		cout << s[i] << ' ';
}
int main()
{
	
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> a[i];
	jishupaixu(a, n);
	print(a, n);
}

桶排序

桶排序确实比较拉胯,它的意思是分一些桶,把数据放在一个区间范围内的桶中,然后分别排每一个桶,最后输出;

但是桶的数据结构也很拉胯,

  1. 数组会增加空间消耗
  2. vector会增加时间消耗
  3. list直接是冒泡排序级别的

所以一般不用,如果要使用,就是先分成几个区间中的桶,然后对每个桶使用sort。。。。。。。。。

两种大神级别排序

归并排序

代码实现

  1. 注意这里有一个临时数组:b
  2. 在归并实现的时候:
    • 是左右两个数组比较后放入备份数组
      1. 是否有效,即有没有用完
      2. 大小关系
#include <iostream>
using namespace std;
int a[1000];
int b[1000];

void my_sort(int l, int mid, int r)
{
	int lpos = l, rpos = mid + 1;
	for (int i = l; i <= r; i++)
	{
		if (lpos <= mid && (a[lpos] <= a[rpos] || rpos > r))
		{
			b[i] = a[lpos++];
		}
		else
		{
			b[i] = a[rpos++];
		}
	}
	for (int i = l; i <= r; i++)
		a[i] = b[i];
}
void dive(int l, int r)
{
	int mid = (l + r) / 2;
	if (l < r)
	{
		dive(l, mid);
		dive(mid + 1, r);
	}
	my_sort(l, mid, r);
}
void print(int s[], int n)
{
	for (int i = 0; i < n; i++)
		cout << s[i] << ' ';
}
int main()
{
	
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> a[i];
	dive(0, n - 1);
	print(a, n);
}

快速排序

#include <iostream>
using namespace std;
int a[1000];
int b[1000];
void quike_sort(int l, int r)
{
	int i = l;
	int j = r;
	int mid = (l + r) >> 1;
	int t = a[mid];//一定要拿出这个基准值,因为后面会变化
	while (i <= j)
	{
		while (a[i] < t) i++;//一定是小于,为了让左指针在基准值之前停留下来
		while (a[j] > t) j--;//同上
		if (i <= j)
		{
			int tmp = a[i];
			a[i] = a[j];
			a[j] = tmp;
			i++;
			j--;
		}
	}
	if (l < j)
		quike_sort(l, j);
	if (i < r)
		quike_sort(i, r);

}

void print(int s[], int n)
{
	for (int i = 0; i < n; i++)
		cout << s[i] << ' ';
}
int main()
{
	
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> a[i];
	quike_sort(0, n-1);
	print(a, n);
}
posted @ 2022-01-04 09:26  心坚石穿  阅读(34)  评论(0)    收藏  举报