(一)算法之七大排序-C++

目录

1.冒泡排序

2.简单选择排序

3.直接插入排序算法

4.希尔排序

5. 堆排序

6.归并排序

7.快速排序

8. 总结与算法时间复杂度分析

附录


排序:假设有n个记录的序列{r1,r2,...rn},其相应的关键字分别为{k1,k2,...kn},需确定1,2,....,n的一种排列p1,p2,......pn,使其相应的关键字满足非递减或非递增关系,即使得序列成为一个按关键字有序的序列,这样的操作即为排序。

根据在排序过程中待排序的记录是否全部放在内存中,分为内排序和外排序。内排序主要受时间性能辅助空间算法复杂性实现的。

按照算法复杂度将排序分为两大类,即

       (1)简单算法:冒泡排序、简单选择排序、插入排序 ;

       (2)改进算法:希尔排序、堆排序、归并排序、快速排序  ;


1.冒泡排序

冒泡排序:一种交换排序。基本思想是,两两比较相邻记录关键字,如果反序交换,直到没有反序的记录为止。

如果待排序的序列为{2,1,3,4,5,6,7,8,9}时,如果仍遍历所有,进行比较,则作了很多无用功。因此需要改进一下,增加标记变量flag来实现算法改进。

//02冒泡排序算法
void sortMethod02(Data *list)
{
	bool flag = true;
	for (int i = 1;i <= list->length&&flag;i++)
	{
		flag = false;
		for (int  j = list->length-1; j >= i; j--)
		{
			if (list->r[j]<list->r[j-1])
			{
				swap(list, j, j - 1);
				flag = true;
			}
		}
	}
}

2.简单选择排序

简单选择排序:通过n-i次关键字间的比较,从n-i+1个记录中选出最小的关键字,并和第i(1\leq i\leq n)个记录交换之。

简单选择排序的性能上略优于冒泡排序。

//03简单选择排序算法
void sortMethod03(Data *list)
{
	int min;
	for (int  i = 1; i <= list->length; i++)
	{
		min = i;
		for (int  j = i+1; j <= list->length; j++)
		{
			if (list->r[min] > list->r[j])
			{
				min = j;
			}
		}
		if (min != i)
		{
			swap(list, i, min);
		}
	}
}

3.直接插入排序算法

直接插入排序算法:将一个数字插入到已经排好序的有序表中,从而得到一个新的,记录增加1的有序表。

直接插入排序法比冒泡和简单选择排序性能要好一些。

直接插入排序在下列两种情况比较有优势

(1)序列本身基本有序,只需要少量的插入操作,就可以完成整个序列的排序工作;

(2)序列内数字个数比较;

//04 直接插入排序
void sortMethod04(Data *list)
{
	int j;
	for (int i = 2; i <= list->length; i++)
	{
		if (list->r[i]<list->r[i-1])
		{
			list->r[0] = list->r[i];//r[0]为哨兵位置
			for (j = i-1;list->r[j]>list->r[0]; j--)
			{
				list->r[j + 1] = list->r[j];				
			}
			list->r[j + 1] = list->r[0];
		}
	}
}

4.希尔排序

希尔排序:首先将整个序列中相距某个“增量”的记录组成多个子序列,然后在各个子序列中分别进行直接插入排序,从而得到基本有序的序列,再对整个序列进行一次直接插入排序。其特点为跳跃式移动,而非一步一步往前挪动。

针对希尔排序的说明:

(1)“增量”的选取非常关键,迄今为止,还没有找到一种最好的增量序列。但研究表明,当序列为delta[k]=2^{t-k+1}(0\leq k\leq t\leqslant [log_{2}(n+1))])时,可以获得不错的效果;“增量”数列的最后一个增量值必须等于1才行。

(2)基本有序:小的关键字基本在前面,大的基本在后面,不大不小的基本在中间。

//05 希尔排序
void sortMethod05(Data *list)
{
	int i, j;
	int delta = list->length;
	do
	{
		delta = delta / 3 + 1;
		for ( i = delta+1; i <= list->length; i++)
		{
			if (list->r[i]<list->r[i-delta])
			{
				list->r[0] = list->r[i];
				for ( j = i-delta; j>0&&list->r[0]<list->r[j]; j-=delta)
				{
					list->r[j + delta] = list->r[0];
				}
				list->r[j + delta] = list->r[0];
			}
		}

	} while (delta>1);
}

5. 堆排序

堆排序:利用进行排序的方法。

基本思想:将待排序的序列后成一个大顶堆。此时,整个序列最大值就是堆顶的根节点。将它移走(即与对数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构成一个大顶堆,这样就会得到n个元素中的次大值。如此反复执行,便得到一个有序序列。

关键步骤:(1)由无序序列构建堆。(2)在输出堆顶元素后,调整剩余元素生成一个新的堆。

特点:堆排序性能远远好过于冒泡、简单选择、直接插入的时间复杂度。

           堆排序是一种不稳定的排序方法。

           由于初始构建堆需要比较次数较多,因此,并不适合排序序列个数较少的情况。

//06 堆排序
void createHeap(Data *list, int begin, int end);
void sortMethod06(Data *list)
{
	for (int i = 1; i <= (list->length)/2; i++)
	{
		createHeap(list,i,list->length);
	}

	for (int i = list->length; i >1; i--)
	{
		swap(list, 1, i);
		createHeap(list, 1, i - 1);
	}
}
void createHeap(Data *list, int begin, int end)
{
	int temp, j;
	temp = list->r[begin];
	for ( j = 2*begin; j <= end; j*=2)
	{
		if (j < end&&list->r[j] < list->r[j + 1])
			++j;
		if (temp >= list->r[j])
			break;
		list->r[begin] = list->r[j];
		begin = j;
	}
	list->r[begin] = temp;

}

6.归并排序

归并排序:就是利用归并的思想。

2路归并排序:假设初始序列含有n个记录,则可以看成是有n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[\frac{n}{2}]([x]表示不小x的最小整数)个长度为2或1的有序子序列;再两两归并,...,如此重复,直至得到一个长度为n的有序序列位置。这种排序方法为2路归并排序。

void MSort(int SR[],int TR1[],int s,int t);
void Merge(int SR[], int TR1[], int i, int m, int n);
void sortMethod07(Data *list)
{
	MSort(list->r, list->r, 1, list->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;
		MSort(SR, TR2, s, m);
		MSort(SR, TR2, m+1, t);
		Merge(TR2, TR1, s, m, t);
	}
}
void Merge(int SR[], int TR[], int i, int m, int n)
{
	int j, k, l;
	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 ( l = 0; l <= m-i; l++)
		{
			TR[k + l] = SR[i + 1];
		}
	}
	if (j <= n)
	{
		for (l = 0; l <= n - j; l++)
		{
			TR[k + l] = SR[j + 1];
		}
	}

}

7.快速排序

快速排序:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

void QSort(Data *list, int low, int high);
int Partition(Data *list, int low, int high);
void sortMethod08(Data *list)
{
	QSort(list,1,list->length);
}
void QSort(Data *list, int low, int high)
{
	int pivot;
	if (low<high)
	{
		pivot = Partition(list, low, high);

		QSort(list, low, pivot - 1);
		QSort(list, high, high);

	}
}

int Partition(Data *list, int low, int high)
{
	int pivotkey;
	pivotkey = list->r[low];
	while (low < high)
	{
		while (low<high&&list->r[high]>=pivotkey)
		{
			high--;
		}
		swap(list, low, high);
		while (low < high&&list->r[low] <= pivotkey)
			low++;
		swap(list, low, high);
	}
	return low;
}

8. 总结与算法时间复杂度分析

以上为七大排序方法,主要归属于插入排序、交换排序、选择排序和归并排序四类。

排序
插入排序类选择排序类交换排序类归并排序类

直接插入

排序

希尔排序简单选择排序堆排序冒泡排序快速排序归并排序

上述算法的时间复杂度对比

排序方式平均情况最好情况最坏情况辅助空间稳定性
冒泡排序O(n^{2})O(n)O(n^{2})O(1)稳定
简单选择排序O(n^{2})O(n^{2})O(n^{2})O(1)稳定
直接插入排序O(n^{2})O(n)O(n^{2})O(1)稳定
希尔排序O(nlogn)~O(n^{2})O(n^{1.3})O(n^{2})O(1)不稳定
堆排序O(nlogn)O(nlogn)O(nlogn)O(1)不稳定
归并排序O(nlogn)O(nlogn)O(nlogn)O(n)稳定
快速排序O(nlogn)O(nlogn)O(n^{2})O(logn)~O(n)不稳定

附录

附上所有代码:

//七大排序
#include<iostream>
using namespace std;

#define MaxSize 10 //待排序个数

struct Data
{
	int r[MaxSize + 1];//取多出的一个作为临时变量
	int length;
};

void swap(Data *list, int i, int j)
{
	int temp = list->r[i];
	list->r[i] = list->r[j];
	list->r[j] = temp;
}


//01最简单的排序
void sortMethod01(Data *list)
{
	for (int i = 1; i <= list->length; i++)
	{
		for (int j = i + 1; j <= list->length; j++)
		{
			if (list->r[i] > list->r[j])
			{
				swap(list, i, j);
			}
		}
	}
}

//02冒泡排序算法
void sortMethod02(Data *list)
{
	bool flag = true;
	for (int i = 1;i <= list->length&&flag;i++)
	{
		flag = false;
		for (int  j = list->length-1; j >= i; j--)
		{
			if (list->r[j]<list->r[j-1])
			{
				swap(list, j, j - 1);
				flag = true;
			}
		}
	}
}

//03简单选择排序算法
void sortMethod03(Data *list)
{
	int min;
	for (int  i = 1; i <= list->length; i++)
	{
		min = i;
		for (int  j = i+1; j <= list->length; j++)
		{
			if (list->r[min] > list->r[j])
			{
				min = j;
			}
		}
		if (min != i)
		{
			swap(list, i, min);
		}
	}
}

//04 直接插入排序
void sortMethod04(Data *list)
{
	int j;
	for (int i = 2; i <= list->length; i++)
	{
		if (list->r[i]<list->r[i-1])
		{
			list->r[0] = list->r[i];
			for (j = i-1;list->r[j]>list->r[0]; j--)
			{
				list->r[j + 1] = list->r[j];				
			}
			list->r[j + 1] = list->r[0];
		}
	}
}

//05 希尔排序
void sortMethod05(Data *list)
{
	int i, j;
	int delta = list->length;
	do
	{
		delta = delta / 3 + 1;
		for ( i = delta+1; i <= list->length; i++)
		{
			if (list->r[i]<list->r[i-delta])
			{
				list->r[0] = list->r[i];
				for ( j = i-delta; j>0&&list->r[0]<list->r[j]; j-=delta)
				{
					list->r[j + delta] = list->r[0];
				}
				list->r[j + delta] = list->r[0];
			}
		}

	} while (delta>1);
}

//06 堆排序
void createHeap(Data *list, int begin, int end);
void sortMethod06(Data *list)
{
	for (int i = 1; i <= (list->length)/2; i++)
	{
		createHeap(list,i,list->length);
	}

	for (int i = list->length; i >1; i--)
	{
		swap(list, 1, i);
		createHeap(list, 1, i - 1);
	}
}
void createHeap(Data *list, int begin, int end)
{
	int temp, j;
	temp = list->r[begin];
	for ( j = 2*begin; j <= end; j*=2)
	{
		if (j < end&&list->r[j] < list->r[j + 1])
			++j;
		if (temp >= list->r[j])
			break;
		list->r[begin] = list->r[j];
		begin = j;
	}
	list->r[begin] = temp;

}

//07 归并排序-递归方法
void MSort(int SR[],int TR1[],int s,int t);
void Merge(int SR[], int TR1[], int i, int m, int n);
void sortMethod07(Data *list)
{
	MSort(list->r, list->r, 1, list->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;
		MSort(SR, TR2, s, m);
		MSort(SR, TR2, m+1, t);
		Merge(TR2, TR1, s, m, t);
	}
}
void Merge(int SR[], int TR[], int i, int m, int n)
{
	int j, k, l;
	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 ( l = 0; l <= m-i; l++)
		{
			TR[k + l] = SR[i + 1];
		}
	}
	if (j <= n)
	{
		for (l = 0; l <= n - j; l++)
		{
			TR[k + l] = SR[j + 1];
		}
	}

}

//08 快速排序
void QSort(Data *list, int low, int high);
int Partition(Data *list, int low, int high);
void sortMethod08(Data *list)
{
	QSort(list,1,list->length);
}
void QSort(Data *list, int low, int high)
{
	int pivot;
	if (low<high)
	{
		pivot = Partition(list, low, high);

		QSort(list, low, pivot - 1);
		QSort(list, high, high);

	}
}

int Partition(Data *list, int low, int high)
{
	int pivotkey;
	pivotkey = list->r[low];
	while (low < high)
	{
		while (low<high&&list->r[high]>=pivotkey)
		{
			high--;
		}
		swap(list, low, high);
		while (low < high&&list->r[low] <= pivotkey)
			low++;
		swap(list, low, high);
	}
	return low;
}


//01最简单的排序调用
void Test01(Data *list)
{
	sortMethod01(list);
	cout << "最简单的排序调用结果为:" << endl;
	for (int i = 1; i <= list->length; i++)
	{
		cout << list->r[i] << " ";
	}
	cout << endl;
}
//02冒泡排序调用
void Test02(Data *list)
{
	sortMethod02(list);
	cout << "冒泡排序调用结果为:" << endl;
	for (int i = 1; i <= list->length; i++)
	{
		cout << list->r[i] << " ";
	}
	cout << endl;
}

//03简单选择排序调用
void Test03(Data *list)
{
	sortMethod03(list);
	cout << "简单选择排序调用结果为:" << endl;
	for (int i = 1; i <= list->length; i++)
	{
		cout << list->r[i] << " ";
	}
	cout << endl;
}

//04直接插入排序调用
void Test04(Data *list)
{
	sortMethod04(list);
	cout << "简单选择排序调用结果为:" << endl;
	for (int i = 1; i <= list->length; i++)
	{
		cout << list->r[i] << " ";
	}
	cout << endl;
}

//05 希尔排序
void Test05(Data *list)
{
	sortMethod05(list);
	cout << "希尔排序调用结果为:" << endl;
	for (int i = 1; i <= list->length; i++)
	{
		cout << list->r[i] << " ";
	}
	cout << endl;
}

//06 堆排序
void Test06(Data *list)
{
	sortMethod06(list);
	cout << "堆排序调用结果为:" << endl;
	for (int i = 1; i <= list->length; i++)
	{
		cout << list->r[i] << " ";
	}
	cout << endl;
}

//07 归并排序
void Test07(Data *list)
{
	sortMethod07(list);
	cout << "归并排序调用结果为:" << endl;
	for (int i = 1; i <= list->length; i++)
	{
		cout << list->r[i] << " ";
	}
	cout << endl;
}

//08 快速排序
void Test08(Data *list)
{
	sortMethod08(list);
	cout << "快速排序调用结果为:" << endl;
	for (int i = 1; i <= list->length; i++)
	{
		cout << list->r[i] << " ";
	}
	cout << endl;
}

int main()
{
	//初始化
	Data list = 
	{ { 0,9,1,5,8,3,7,4,6,2 },
		9 
	};

	//test
	Test01(&list);
	Test02(&list);
	Test03(&list);
	Test04(&list);
	Test05(&list);
	Test06(&list);
	Test07(&list);
	Test08(&list);

	cin.get();
	system("pause");
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值