五种排序算法的C++实现(选择、插入、希尔、归并、快速)

函数声明

#include <iostream>
#include <cstdlib>
#define random(x) (rand()%x)				// 产生0~x的随机数,用于打乱数组 

using namespace std;
const int length = 10;						// 数组大小 
typedef int T;
static T spt[length];

bool less1(T v, T w);				// 比较两元素大小,如果v<w,返回true,反之返回false
void exch(T* a, int i, int j);		// 交换数组中两个元素
void show(T* a, int l);				// 打印数组
bool isSorted(T* a, int l);			// 判断数组元素是否有序

void selectSort(T* a, int l);		// 选择排序

void insertSort(T* a, int l);		// 插入排序 

void shellSort(T* a, int l);		// 希尔排序 

void mergeSort(T* a, int l);		// 归并排序

/* merge函数将子数组a[low...mid]和a[mid+1...high]归并成
一个有序的数组,并将结果存放在a[low...high]中 */ 
void merge(T* a, int low, int mid, int high);
void mergeSort(T* a, int low, int high); 

void shuffle(T* a, int l);				  // 打乱数组 
int partition(T* a, int low, int high);   // 快速排序的切分 
void quickSort_S(T* a, int low, int high);// 快速排序的内部行为 
void quickSort(T* a, int l);		// 快速排序 

辅助函数如下:(函数的功能如其名字所示)

bool less1(T v, T w) {
	return v < w;
}

void exch(T* a, int i, int j) {
	T t = *(a+i);
	*(a+i) = *(a+j);
	*(a+j) = t;
}

void show(T* a, int l) {
	for (int i = 0; i < l; i++)
		cout << *(a+i) << " ";
	cout << endl;
}

bool isSorted(T* a, int l) {
	for (int i = 0; i < l; i++)
		if (less1(*(a+i), *(a+i-1))) return false;
	return true;
}

选择排序的算法思想是这样的:
首先,找到数组中最小的那个元素,然后将它和数组的第一个元素交换位置。接着再在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置,如此往复直到将整个数组排序。

void selectSort(T* a, int l) {
	for (int i = 0; i < l; i++) {
		// 将a[]按升序排序 
		int min = i;			// 最小元素索引 
		for (int j = i+1; j < l; j++)
			if (less1(*(a+j), *(a+min))) min = j;
		exch(a, i, min); 
	}
}

插入排序:
将每一个元素插入到其他已经有序的元素中的适当位置,为了要给插入的元素腾出空间,需要将其余所有元素在插入之前都向右移动一位。
(对于随机排列的长度为N且主键不重复的数组,平均情况下插入排序需要N2/4次比较以及N2/4次交换。最坏情况下需要N2/2次比较和N2/2次交换,最好情况下需要N-1次比较和0次交换)

void insertSort(T* a, int l) {
	// 将a[]按升序排列
	for (int i = 0; i < l; i++) {
		// 将a[i]插入到a[i-1],a[i-2],a[i-3]...之中
		for (int j = i; j > 0 && less1(*(a+j), *(a+j-1));j--) 
			exch(a, j, j-1);
	} 
}

希尔排序:
希尔排序是一种基于插入排序的排序算法。即交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。
希尔排序的思想是使数组中任意间隔为h的元素都是有序的,这样的数组被称为h有序数组。在进行排序时,如果h很大,就能将元素移动到很远的地方。
下面的这个算法使用了1/2(3h-1),从N/3开始递减至1

void shellSort(T* a, int l) {
	// 将a[]按升序排列
	int h = 1;
	while (h < l/3) h = 3*h + 1;  // 1, 4, 13, 40, 121, 364, 1093...
	while (h >= 1) {
		// 将数组变为h有序
		for (int i = h; i < l; i++) {
			for (int j = i; j >= h && less1(*(a+j), *(a+j-h)); j -= h)
				exch(a, j, j-h); 
		}
		h = h/3;
	} 
}

归并排序:
递归地将它分成两半分别排序,然后将结果归并起来。
归并排序地性质是能够保证将任意长度为N地数组排序所需时间为NlogN(以2为底),它的主要缺点是它所需的额外空间和N成正比

void merge(T* a, int low, int mid, int high) {
	// 将数组a[low...mid] 和 a[mid+1...high]归并
	int i = low, j = mid+1;
	
	for (int k = low; k <= high; k++)
		spt[k] = *(a+k);			//	将a[low...high]复制到spt中
	
	for (int k = low; k <= high; k++)  // 归并回到a[low...high]
		if (i > mid)	*(a+k) = spt[j++];
		else if (j > high)	*(a+k) = spt[i++];
		else if (less1(spt[j], spt[i])) *(a+k) = spt[j++];
		else	*(a+k) = spt[i++]; 
}

void mergeSort(T* a, int low, int high) {
	// 将数组a[low...high]排序
	if (high <= low) return;
	int mid = low + (high - low) / 2;
	mergeSort(a, low, mid);
	mergeSort(a, mid+1, high);
	merge(a, low, mid, high); 
}

void mergeSort(T* a, int l) {
	mergeSort(a, 0, l-1);
}

快速排序:
快速排序是一种分治的排序算法。它将一个数组分成两个子数组,将两部分独立地排序。递归调用发生在处理整个数组之后,因此和归并排序是互补的。在快速排序中,切分(partition)的位置取决于数组的内容。

void shuffle(T* a, int l) {
	for (int i = 0; i < l; i++) {
		int local = (int)random(l);
		T temp = *(a+i);
		*(a+i) = *(a + local);
		*(a+local) = temp;
	}
}

int partition(T* a, int low, int high) {
	int i = low, j = high+1;
	T v = *(a+low);
	while (1) {
		// 扫描左右,检查扫描是否结束并交换元素
		while (less1(*(a+(++i)), v)) if (i == high) break;
		while (less1(v, *(a+(--j)))) if (j == low)  break;
		if (i >= j) break;
		exch(a, i, j); 
	}
	exch(a, low, j);		// 将v = a[j]放入正确的位置
	return j;				// a[low...j-1] <= a[j] <= a[j+1...high] 
}

void quickSort_S(T* a, int low, int high) {
	if (high <= low) return;
	int j = partition(a, low, high);
	quickSort_S(a, low, j-1);
	quickSort_S(a, j+1, high);
}

void quickSort(T* a, int l) {
	shuffle(a, l);
	quickSort_S(a, 0, l-1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值