算法基础之排序

    算法的重要性我想就不必多说了,程序的灵魂所在,也是我们解决很多问题的重要工具,可以说是程序猿的必学知识!

本篇主要介绍关于排序方面的算法,本人水平有限,出于学习之中,如有错误之处,望各位大牛批评指正!


排序的种类很多,时间效率和空间效率也不尽相同,各有利弊,不同的排序算法适用于不同的特征数据。

  1. 插入排序 , 简单直观,将待排序的元素插入到已排序好的子序列中,又可分为直接插入排序、折半插入排序和希尔排序
直接插入代码如下:适用于基本有序的数据,且数据量不大
// 对数组A[] 的A[1]到A[n] 排序
void InsertSort(ElemType A[] , int s){
	int i , j ;
	for (int i = 2; i < s; i++)
	{
		if (A[i] < A[i-1]){
			A[0] = A[i];  // 哨兵A[0]
			for (int j = i-1; A[0]  < A[j];  --j)
				A[j+1] = A[j]; // 向后挪位置,
			A[j+1] = A[0]; //  插入
		}
	}
}
折半插入代码如下:是上者的改进,但效率并未提升
//折半插入, 对数组A[] 的A[1]到A[n] 排序
void InsertSort(ElemType A[] , int s){
	int i , j , low ,high, mid ;
	for (int i = 2; i <= s; i++)
	{
		A[0] = A[i] ;
		low = 1 ; high = i -1 ;
		while (low <= high)
		{
			mid = (low + high) / 2;
			if (A[mid] > A[0])
				high = mid -1; //左半边查找
			else
				low = mid +1 ;//右半边查找
		}
		for (int j = i-1; A[0]  < A[j];  --j)
				A[j+1] = A[j]; // 向后挪位置,
		A[j+1] = A[0]; //  插入
	}
}
希尔排序代码:将排序表分割成以 特定步长 为单位的子表,然后进行直接插入排序
//希尔排序, 对数组A[] 的A[1]到A[n] 排序
void ShellSort(ElemType A[] , int s){
	// 记步长为dk
	for (int dk = A[].lenth / 2 ; dk >= 1 ; dk = dk/2)
		for (int i = dk + 1; i <= s; i++)
		{
			if (A[i] < A[i - dk] )
			{
				A[0] = A[i];  // 哨兵A[0]
				for (int j = i-dk; j > 0 && (A[0]  < A[j]);  j-=dk)
					A[j+dk] = A[j]; // 向后挪位置,
				A[j+dk] = A[0]; //  插入
			}
		}
}

2.交换排序, 基于交换的排序有很多,这里只介绍几个重要的,冒泡和快排
冒泡排序基本思想是从后往前或者从前往后两两比较相邻元素的值,若为逆序,则交换之,直至排序完成。
代码函数如下:
//冒泡排序
void  BubbleSort(ElemType A[] , int n){
	for (int i = 0; i < n-1; i++)
	{
		flag = false;  //本趟冒泡如未发生交换,说明已排序好
		for (int j = n-1; j > i; j--)  //一次冒泡
		{
			if (A[j-1] > A[j]){
				swap(A[j-1] , A[j] ); // 交换
				flag = true;
			}
		}
		if (flag == false)
			return ; 
	}
}

快速排序是对冒泡排序的一种改进。基于分治的思想,找到一个元素的最终位置,作为枢轴值,然后左半边和右半边递归
代码如下:
//快速排序,递归
void QuickSort(ElemType A[], int low, int high){
	if (low < high)
	{
		int pivot = Partition( A[] , low , high );
		QuickSort( A[],  low, pivot -1);
		QuickSort( A[], pivot +1 , high);
	}
}
// 找出枢轴值pivot, 该元素将序列划分为两部分
int  Partition(ElemType A[], int low, int high){
	// 即一趟快排结果
	ElemType pivot = A[low]; // 将第一个元素作为初始枢轴值
	while (low < high)
	{
		while (low < high && A[high] >= pivot)  --high;
		A[low] = A[high] ;
		while (low < high && A[low] >= pivot)  ++low;
		A[high] = A[low] ;
	}
	A[low] = pivot;
	return low ; //返回枢轴最终位置
}

3. 选择排序,选择排序顾名思义,每次选择出一个最小的元素,挨个排在后面,
简单选择排序,思想是:第i趟排序从A[i ... n] 中选择关键字最小的元素与A[i] 交换
代码如下:
//简单选择排序
void SelectSort (ElemType A[], int n){
	for (int i = 0; i < n-1; i++)
	{
		min = i ;		 //记录最小元素
		for (int j = i+1; j < n; j++)  //选择出最小的元素
			if (A[j] < A[min])   min = j ;
		if (min != i )   //与第i个元素交换
			swap(A[i] , A[min]);
	}
}

堆排序也是选择排序的一种,而且是非常重要的排序,笔者的下一篇博客会详细介绍。

4.归并排序基数排序
归并排序也是一种很重要的排序,而且时间效率跟堆排序一样,都是很快的排序。
下面介绍2-路归并排序,你看到下面的图也许就会明白2-路归并的思想。


分解排序,然后合并之。
代码如下:
//归并排序, 要额外的临时空间 B[] 数组
// 合并函数
void Merge(ElemType A[], int low, int mid ,  int high){
	for (int k = low ; k <= high ; k++)
		B[k] = A[k] ;
	for (int i = low , j = mid +1 , k = i ; i <= mid  && j <= high ; k++)
	{
		if (B[i] <= B[j])
			A[k] = B[i++];
		else
			A[k] = B[j++];
	}
	// 将未检测完的一次性加到后面,并且下面的两个
	// while 循环只会执行一个
	while (i <= mid)      A[k++] = B[i++] ;
	while (i <= mid)      A[k++] = B[j++] ;
}
// 归并排序
void  MergeSort (ElemType A[], int low, int high) {
	if (low < high)
	{
		int mid = ( low + high )/2;  // 从中间划分成两个子序列
		MergeSort (A[], int low, int mid);  //对左边子序列进行递归排序
		MergeSort (A[], int mid +1 , int high);  //对右边子序列进行递归排序
		Merge (A[],  low, mid , high);  // 合并
	}
}

基数排序也是一种很实用的排序,但有点特别,它是基于关键的重要性进行排序,有分配和收集两个步骤 ,因为关键字不尽相同,所以笔者在这里就不进行代码分享了。

笔者处于学习阶段,难免会有错误疏漏之处,还请各位大牛批评指正!奋斗

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值