程序员必备排序算法

(一)冒泡排序(稳定)
1.基本思想:每一趟从数组的头部开始,两两做比较,根据大小进行位置的交换,直到最后一个数到达末尾,即该数为此趟的最大值,在循环中继续重复此操作,最终得到排序好的序列
2.时间复杂度:
最优的情况也就是开始就已经排序好序了,那么就可以不用交换元素了,则时间花销为:[ n(n-1) ] / 2;所以最优的情况时间复杂度为:O( n^2 );

最差的情况也就是开始的时候元素就是逆序的,那么每一次排序都需要交换元素,则时间花销为:[3n(n-1) ] / 2;所以最差的情况时间复杂度为:O( n^2 );
综上所述:
最优时间复杂度:O(n^2);
最差时间复杂度:O(n^2);
平均时间复杂度:O(n^2);

3.空间复杂度(空间复杂度就是在交换元素时那个临时变量所占的内存空间):
最优的空间复杂度就是开始元素顺序已经排好了,则空间复杂度为:0;
最差的空间复杂度就是开始元素逆序排序了,则空间复杂度为:O(n);
平均的空间复杂度为:O(1);

4.代码实现:

void bubble_sort(int a[], int n)
{
	int t;
	for(int i=0;i<n-1;i++)
		for (int j = 0; j < n-1-i; j++)
			if (a[j] > a[j + 1]) {
				t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
			}
}

(二)选择排序(不稳定)
1.基本思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。重复第二步,直到所有元素均排序完毕。
2.时间复杂度:
比较时间:T=(n-1)+(n-2)+…+1=n(n-1)/2
交换时间:全部有序,则交换次数为0;全部逆序,则交换次数为n-1
综上所述:
最优时间复杂度:O(n^2);
最差时间复杂度:O(n^2);
平均时间复杂度:O(n^2);
3.空间复杂度:同冒泡排序
4.代码实现:

void select_sort(int a[], int n)
{
	int i,j,min;
	for (i = 0; i < n - 1; i++)
	{
		min = i;
		for (j = i + 1; j < n; j++)
		{
			if (a[j] < a[min])
				min = j;
		}
		int t;
		t = a[i]; a[i] = a[min]; a[min] = t;
	}
}

(三)插入排序(稳定)
1.基本思想:将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
2.时间复杂度:O(n^2);
3.空间复杂度:O(1);
4.代码实现:

void insert_sort(int a[], int n)
{
	int i,j,key;
	for (i = 1; i < n; i++)
	{
		key = a[i];
		j = i - 1;
		while (j >= 0 && key < a[j])
		{
			a[j + 1] = a[j];
			j--;
		}
		a[j + 1] = key;
	}
}

(四)快速排序(不稳定)
1.基本思想:在数组中选一个基准数(通常为数组第一个);
将数组中小于基准数的数据移到基准数左边,大于基准数的移到右边;
对于基准数左、右两边的数组,不断重复以上两个过程,直到每个子集只有一个元素,即为全部有序
2.时间复杂度:O(nlogn);
3.空间复杂度:O(nlogn);
4.代码实现:

void quick_sort(int a[], int begin, int end)
{
	if (begin < end)
	{
		int i = begin, j = end,temp=a[begin];
		while (i < j)
		{
			while (i<j&&a[j]>temp)
				j--;
			a[i] = a[j];
			while (i < j&&a[i]<=temp)
				i++;
			a[j] = a[i];
		}
		a[i] = temp;
		quick_sort(a, begin, i - 1);
		quick_sort(a, i + 1, end);
	}
}

(五)堆排序(不稳定)
1.基本思想:
堆的定义如下:n个元素的序列{k1,k2,···,kn}当且满足以下关系时,称之为堆
在这里插入图片描述
对于一个小顶堆,若在输出堆顶的最小值之后, 使剩余n-1个元素的序列再次筛选形成一个堆,再输出次小值,由此反复进行,便能得到一个有序的序列,这个过程就称之为堆排序。
2.时间复杂度:O(nlogn);
3.空间复杂度:O(1);
4.代码实现:

#include <iostream>
const int N =10;
using namespace std;
void HeapAdjust(int a[],int s,int m)//一次筛选的过程
{
    int rc,j;
    rc=a[s];
    for(j=2*s;j<=m;j=j*2)//通过循环沿较大的孩子结点向下筛选
    {
        if(j<m&&a[j]<a[j+1]) j++;//j为较大的记录的下标
        if(rc>a[j]) break;
        a[s]=a[j];s=j;
    }
    a[s]=rc;//插入
}
void HeapSort(int a[],int n)
{
    int temp,i,j;
    for(i=n/2;i>0;i--)//通过循环初始化顶堆
    {
        HeapAdjust(a,i,n);
    }
    for(i=n;i>0;i--)
    {
        temp=a[1];
        a[1]=a[i];
        a[i]=temp;//将堆顶记录与未排序的最后一个记录交换
        HeapAdjust(a,1,i-1);//重新调整为顶堆
    }
}
void print(int a[],int n)
{
for(int i=1;i<=n;i++)
    cout<<a[i]<<" ";
}
int main()
{
    int n,i;
    cin>>n;
    int a[N];
    for(i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    HeapSort(a,n);
    print(a,n);
    return 0;
}

(六)归并排序(稳定)
1.基本思想:分而治之
在这里插入图片描述
2.时间复杂度:O(nlogn);
3.空间复杂度:O(n);
4.代码实现:

#include<iostream>
using namespace std;
template<typename T>
void merge(T a[], int first, int mid, int last, T temp[])
{
	int i = first,j=mid+1;
	int m = mid,n=last,k=0;
	while (i <= m && j <= n)
	{
		if (a[i] < a[j])temp[k++] = a[i++];
		else temp[k++] = a[j++];
	}
	while (i <= m)
		temp[k++] = a[i++];
	while(j<=n)
		temp[k++] = a[j++];
	for (i = 0; i < k; i++)
		a[i+first] = temp[i];
}
template<typename T>
void mergesort(T a[], int first, int last, T temp[])
{
	if (first < last)
	{
		int mid = (first + last) / 2;
		mergesort(a, first, mid, temp);
		mergesort(a, mid + 1, last, temp);
		merge(a, first, mid, last, temp);
	}
}
void main()
{
	int a[8] = { 8,3,2,6,7,1,5,4 }, temp[8] = { 0 };
	mergesort(a, 0, 7, temp);
	for (int i = 0; i < 8; i++)
		cout << a[i] << " ";
	cout << endl;
	system("pause");
}

猜你喜欢

转载自blog.csdn.net/weixin_45627193/article/details/107119516