各种排序

数据结构学完了,总结一下排序。没有那种排序永远是最优的,各有千秋吧。

//插入排序
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int * insert_sort(int a[], int n)//直接插入排序
{
	int i,j;
	for(i = 2; i <= n; i++)
	{
		if(a[i-1] > a[i])
		{
			a[0] = a[i]; //复制为监视哨
			a[i] = a[i-1]; //将a[i-1]后移
			for(j = i-2; a[j] > a[0]; j--)
				a[j+1] = a[j];//将j+1与i-2之间的数向后移,j满足a[j+1] > a[0]而a[j] < a[0];
			a[j+1] = a[0];//将待插入的a[i]插入a[j+1]处
		}
	}
	return a;
}

//折半查找
int binsearch(int a[], int low, int high,int num)
{
	while(low <= high)
	{
		int m = (low+high)/2;
		if(a[m] > num)
			high = m-1;
		else if(a[m] < num)
			low = m+1;
	}
	return low;
}

int * biInsertion_sort(int a[], int n)//折半插入排序
{
	int i,j;
	for(i = 2; i <= n; i++)
	{
		if(a[i-1] > a[i])
		{
			a[0] = a[i];
			int low = binsearch(a,1,i-1,a[i]);//通过折半查找找到a[i]插入的位置为a[low];
			for(j = i-1; j >= low; j--)
				a[j+1] = a[j];
			a[low] = a[0];
		}
	}
	return a;
}

int * BubbleSort(int a[], int n)//起泡排序
{
	int i = n,j;
	int lastexchang;
	while(i > 1)
	{
		lastexchang = 1;//初始化最后一次交换位置
		for(j = 1; j < i; j++)
		{
			if(a[j] > a[j+1])
			{
				swap(a[j],a[j+1]);
				lastexchang = j;//更新最后一次交换位置
			}
		}
		i = lastexchang;//lastexchang~n的关键字已经有序,下次从1~lastexchang-1 排序
	}
	return a;
}

int main()
{
	int a[110];
	int n;
	scanf("%d",&n);
	for(int i = 1; i <= n; i++)
		scanf("%d",&a[i]);
	insert_sort(a,n);//对长度为n的数组从小到大直接插入排序
	biInsertion_sort(a,n);//对长度为n的数组从小到大折半插入排序
	BubbleSort(a,n);//对长度为n的数组从小到大起泡排序
	for(int i = 1; i <= n; i++)
		printf("%d ",a[i]);
	return 0;
}

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

//调整堆,从i节点开始从上往下调整,n为节点总数
void MaxHeapFixDown(int *a, int i, int n)
{
	int j = 2*i+1;//i节点的子节点
	int tmp = a[i];

	while(j < n)
	{
		if(j + 1 < n && a[j+1] > a[j])//在节点i的左右孩子中找最大的
			j++;

		if(tmp >= a[j])//如果tmp 均大于其左右孩子,说明已是合法堆
			break;
		//否则就继续向下调整
		a[i] = a[j];
		i = j;
		j = 2*i+1;
	}
	a[i] = tmp;
}

//建立最大堆
void MakeMaxHeap(int *a, int n)
{
	//对叶子节点来说,它们已是合法的最大堆了,所以只需从 n/2-1 开始向下调整就行了
	for(int i = n/2-1; i >= 0; i--)
	{
		MaxHeapFixDown(a,i,n);
	}
}

//堆排序,先建立一个最大堆,那么a[0]肯定是节点中最大的,第一次将a[0]与a[n-1]交换,
//再对a[0~n-2]调整堆,第二次将a[0]与a[n-2]交换,再对a[0~n-3]调整堆,重复这样的操作,
//直到a[0]与a[1]交换,最后得到一个递增的有序序列。
void MaxHeapSort(int * a, int n)
{
	MakeMaxHeap(a,n);
	for(int i = n-1; i >= 1; i--)
	{
		swap(a[i],a[0]);
		MaxHeapFixDown(a,0,i);
	}
}

int main()
{
	int n,a[110];
	scanf("%d",&n);
	for(int i = 0; i < n; i++)
		scanf("%d",&a[i]);

	MaxHeapSort(a,n);

	for(int i = 0; i < n; i++)
		printf("%d ",a[i]);
	printf("\n");
	return 0;
}

//归并排序
//划分问题,把序列分成元素个数尽量相等的两半
//递归求解,把两半元素分别排序
//合并问题,把两个有序表合并成一个
#include<stdio.h>
#include<string.h>
void merge_sort(int *a, int x, int y, int *t)
{
	if(y - x > 1)
	{
		int m = x + (y-x)/2;//划分
		int p = x, q = m, i = x;
		merge_sort(a,x,m,t);//递归求解
		merge_sort(a,m,y,t);//递归求解
		while(p < m || q < y)
		{
			if(q >= y || (p < m && a[p] <= a[q]))
				t[i++] = a[p++];//从左半数组复制到临时空间
			else t[i++] = a[q++];//从右半数组复制到临时空间
		}
		for(int i = x; i < y; i++)
			a[i] = t[i];//从辅助空间复制回a数组
	}
}
int main()
{
	int n;
	int a[110];
	scanf("%d",&n);
	for(int i = 0; i < n; i++)
		scanf("%d",&a[i]);
	int * t = new int [n];//开辟辅助存储空间
	merge_sort(a,0,n,t);
	for(int i = 0; i < n; i++)
		printf("%d ",a[i]);
	return 0;
}

//快速排序的时间复杂度为O(nlogn)
//若待排记录的初始状态为按关键字有序时,快速排序将蜕化为起泡排序,其时间复杂度为O(n2)。
#include<stdio.h>
#include<string.h>
//一趟快速排序
int Partition(int a[], int low, int high)
{
    int t = a[low];// 枢轴
    while(low < high)
    {
        while(low < high && a[high] >= t)
            high--;// 从右向左搜索
        a[low] = a[high];

        while(low < high && a[low] <= t)
            low++;// 从左向右搜索
        a[high] = a[low];
    }
    a[low] = t;
    return low;
}

void Qsort(int a[],int s, int t)
{
    int pivotloc;
    if(s < t)// 长度大于1
    {
        pivotloc = Partition(a,s,t); // 对 a[s..t] 进行一次划分
        Qsort(a,s,pivotloc-1); // 对低子序列递归排序,pivotloc是枢轴位置
        Qsort(a,pivotloc+1,t);// 对高子序列递归排序
    }
}
int main()
{
    int a[110],n;
    scanf("%d",&n);
    for(int i = 0; i < n; i++)
        scanf("%d",&a[i]);
    Qsort(a,0,n-1);
    for(int i = 0; i < n-1; i++)
        printf("%d ",a[i]);
    printf("%d\n",a[n-1]);
    return 0;
}

时间性能分析:
1.  平均的时间性能:
基数排序时间复杂度为O(n);
归并排序,堆排序,快速排序的时间复杂度为Ο(nlogn);
直接插入排序、起泡排序和简单选择排序时间复杂度为  O(n2);


2. 当待排记录序列按关键字顺序有序时:
直接插入排序和起泡排序能达到O(n)的时间复杂度;    
快速排序的时间性能蜕化为O(n2) 


3. 简单选择排序、堆排序和归并排序的时间性能不随记录序列中关键字的分布而改变。
二、空间性能(指的是排序过程中所需的辅助空间大小):
1. 所有的简单排序方法(包括:直接插入、起泡和简单选择) 和堆排序的空间复杂度为O(1);
2. 快速排序为O(logn),为递归程序执行过程中,栈所需的辅助空间;
3. 归并排序所需辅助空间最多,其空间复杂度为 O(n);
4. 链式基数排序需附设队列首尾指针,则空间复杂度为 O(rd)。


三、排序方法的稳定性能:
1. 稳定的排序方法指的是,对于两个关键字相等的记录,它们在序列中的相对位置,在排序之前和经过排序之后,没有改变。
2  快速排序、堆排序和希尔排序是不稳定的排序方法。








   

你可能感兴趣的:(排序)