基础的排序算法

基本概念
稳定性:对于序列中相等的元素a , b,且a在b的前面,若排序之后,a依然在b的前面,则该排序算法是稳定的,否则算法是不稳定的。
时间复杂度:直白的说就是算法才做的次数。
空间复杂度:指执行算法所需要的辅助空间(存储空间)。若存储空间的大小与数据的个数无关,则空间复杂度为O(1)。
说明
为方便讲清楚代码,先定义一个用于排序的顺序结构和一个交换函数。
注意:这里数字的起始位置的下标设置为1

#define MAXSIZE 10 /* 要排序数组的元素个数,可根据需要改变 */
typedef struct
{
	int r [MAXSIZE +1] /* 用于存储排序数组,r[0]用作哨兵或临时变量 */
	int length;
}SqList;

// 也可以使用vector替代
#include<vector> 
vector<int> r(MAXSIZE+1, 0);
viod swap(SqList *L, int i , int j)
{
	int temp = L->r[i];
	L->r[i] = L->r[j];
	L->r[j] = temp;
}

冒泡排序
冒泡算法的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。时间复杂度为O(n^2)

void BubbleSort(SqList* L)
{
	int i, j;
	flag = True;
	for(i = 1; i< L->length && flag; i++)
	{
		flag = False;
		for(j = L->length -1; j >= i; j--)
		{
			if(L->r[j] > L->r[j+1])
			{
				swap(L, j, j+1);
				flag = True;
			}
		}
	}
}

选择排序
选择排序就是通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<= i <=n)个记录交换。
时间复杂度为O(n^2)。尽管选择排序与冒泡排序的时间复杂度一样,但是在性能上还是优于冒泡排序的。

void SelectSort(SqList* L)
{
	int i,j, min;
	for(i = 1;i< L->length;i++)
	{
		min = i;
		for(j = i + 1;j <= L->length;i++)
		{
			if(L->r[min] > L->r[j])
				min = j;
		}
		if(i != min)
			swap(L, i, min);
	}
}

插入排序
插入排序是将一个记录插入到已经排好顺序的有序表中,从而得到一个新的、记录数增加1的有序表。
时间复杂度同样为O(n^2), 但是优于选择排序和冒泡排序。

void InsertSort(SqList* L)
{
	int i,j;
	for(i = 2; i <= L->length; i++)
	{
		if(L->r[i] < L->r[i-1])
		{
			L->r[0] = L->r[i];  /* 设置哨兵  */
			for( j = i -1;L->r[j] > L->r[0]; j--)  /*  找出在已排序的序列中的位置  */
				L->r[j+1] = L->r[j];
			L->r[j+1] = L->r[0];
		}
	}
}

希尔排序
希尔排序是对插入排序的优化,基本思想是:将序列分割成若干个子序列,然后对这些子序列分别进行直接插入排序,当整个序列都基本有序时,注意只是基本有序时,再对全体记录进行一次直接插入排序。
所谓基本有序就是小的关键字基本在前面,大的基本在后面,不大不小的在中间。

void ShellSort(SqList* L)
{
	int i, j;
	int increment = L->length;
	do
	{
		increment = increment/3 + 1;
		for(i = increment+1; i< L->length;i++)
		{
			if(L->r[i] < L->r[i- increment])
			{
				L->r[0] = L->r[i];
				for(j = i-increment; j>0 && L->r[0] < L->r[j]; j-= increment)
					L->r[j+increment] = L->r[j];
				L->r[j+increment] = L->r[0];
			}
		}
	}
	while(increment > 1);
}

堆排序
堆排序就是将待排序的序列构成一个大顶堆。此时整个序列的最大值就是堆顶的根节点。将它与堆数组的末尾元素交换,此时末尾元素就是最大值,然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素的次小值。如此反复执行,就可以得到一个有序序列。
实现堆排序需要解决两个问题:
1.如何由一个无序序列构建一个最大堆?
2.如果在输出对顶元素后,调整剩余元素成为一新的堆?
时间复杂度O(nlogn)

/* 对顺序表L 进行堆排序 */
void HeapSort(Sqort* L)
{
	int i ;
	for(i = L->length/2;i > 0 ;i++)   	/*将待排序的序列构建成一个大顶堆*/
	{
		HeapAdjust(L, i, L->length);
	}
	for(i = L->length;i>1; i--)  /* 逐步将每个最大堆的根节点与末尾元素交换,并且在调整其成为大顶堆。 */
	{
	 	swap(L, l,i);
	 	HeapAdjust(L,1,i-1);
	 }
}


void HeapAdjust( SqList* L, int s, int m)
{
	int temp, j;
	temp = L->r[s];
	for(j = 2*s; j <= m; j*=2)
	{
		if(j < m &&L->r[j] < L->r[j+1])
			j++;
		if(temp >= L->r[j])
			break;
		L->r[s] = L->r[j];
		s = j;
	}
	L->r[s] = temp;
}

归并排序
归并排序的原理是:假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为1或者2 的有序子序列;再两两归并,如此重复,直至得到长度为n的有序序列为止。
时间复杂度O(nlogn),空间复杂度为O(n + logn)

void MergeSort(SqList* L)
{
	MSort(L->r, L->r, 1, L->length);
}

void MSort( int SR[], int TR1[], int s, int t)
{
	int m;
	int TR2[MAXSIZE + 1];
	if(s == t)
		TR1[s] = SR[s];
	else
	{
		m = (s+t) /2;  /*将SR[s .. t]平分为SR[s..m] 和SR[m+1 .. t] */
		MSort(SR,TR2, s, m);   /* 递归将SR[s..m] 归并为有序的TR2[s..m] */
		MSort(SR, TR2, m+1, t);  /* 递归将SR[m+1 .. t] 归并为有序的TR2[m+1 .. t] */
		Merge((TR2, TR1,s, m, t); /*将TR2[s..m]和TR2[m+1 .. t]归并到TR1[s..t] */
	}
}

void Merge(int SR[], int TR[], int i, int m, int n)
{
	int j,k,x;
	for(j = m+1, k = i; i <= m && j <=n;k++)
	{
		if(SR[i] < SR[j])
			TR[k] = SR[i++];
		else
			TR[k] = SR[j++];
	}
	if(i <= m)
	{
		for( x = 0; x<= m-i; x++)
			TR[k+x] = SR{i+x];
	}
	if(j <= n)
	{
		for(x = 0; x<=n-j;n++)
			TR[k+x] = SR[j+x];
	}
}

快速排序
快速排序的基本思想是:通过一趟排序将待排序分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小, 则可分别对这两部分记录继续进行排序,已达到整个序列有序的目的。
时间复杂度O(nlogn)

void QuickSort(SqList *L)
{
	 QSort(L, 1,L->length);
}

void QSort(SqList* L, int low, int high)
{
	int pivot;
	if(low < high)
	{
		pivot = Partition(L,low,high);

		QSort(L,low,pivot-1);
		QSort(L,pivot+1,high);
	}
}

int Partition(SqList* L, int low, int high)
{
	int pivotkey;
	pivotkey = L-> r[low];
	while(low<high)
	{
		while(low < high&&L->r[high} >= pivotkey)
			high--;
		swap(L,low,high);
		while(low<high && L->r[low]<=pivotkey)
			low++;
		swap(L,low, high);
	}
	return low;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值