7种典型的排序算法-代码及原理说明

本文详细介绍了多种排序算法的实现,包括选择排序、插入排序、希尔排序、计数排序、快速排序、归并排序,并提供了相应的代码示例。通过这些排序算法的实现,读者可以深入理解它们的工作原理和效率。

参考连接
参考连接2

// 排序算法1.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<iostream>
using namespace std;

void SelectSort(int Arr[], int size);//选择排序
void InsertSort(int Arr[], int size);//插入排序
void ShellSort(int Arr[], int size);//希尔排序
void CountSort(int Arr[], int size);//计数排序

void RadixSort(int Arr[], int size);//基数排序

void QuickSort(int Arr[], int left, int right);//快速排序

void MergeSort(int Arr[], int size);//归并排序
void _MergeSort(int intArr[], int l, int r);//拆分
void mergeArr(int* intArr, int l, int m, int r);//合并


void swap(int& num1, int& num2);
void Display(int Arr[], int size);
int NumofBitofArr(int iArr[], int size);//求最大的位数

int _tmain(int argc, _TCHAR* argv[])
{
	int Arr[] = { 23, 45,12, 7, 9,26,10,5, 319,18 };
	int size = sizeof(Arr) / sizeof(int);

	/*选择排序
	从头至尾扫描序列,找出最小的一个元素,和第一个元素交换,接着从剩下的元素中继续这种选择和交换方式,
	最终得到一个有序序列。
	*/

	/*插入排序
	每一步将一个待排序的数据插入到前面已经排好序的有序序列中,直到插完所有元素为止
	*/
	//SelectSort(Arr, size);
	//Display(Arr, size);
	/*InsertSort(Arr, size);*/

	//ShellSort(Arr, size);
	/*CountSort(Arr, size);*/

	/*QuickSort(Arr, 0, size-1);*/
	MergeSort(Arr, size);
	Display(Arr, size);
	return 0;
}
/*
选择排序(Selection-sort)是一种简单直观的排序算法。
它的工作原理:首先在未排序序列中找到最小(大)元素
,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,
然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
*/
void SelectSort(int Arr[],int size)
{
	for (int i = 0; i < size-1; i++)//遍历数组下标 从0开始
	{
		int index = i;
		for (int j = i+1; j < size; j++)
		{
			if (Arr[index]>Arr[j])
			{
				index = j;//下标交换
			}
		}
		if (i != index)
		{
			swap(Arr[i], Arr[index]);//数字交换
		}
	}
}
/*
插入排序算法是一种简单直观的排序算法。
它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
*/
void InsertSort(int Arr[], int size)
{
	int temp = 0;
	int j = 0;
	for (int i = 1; i < size; i++)//插入排序认为第一个元素天然有序,从第二个元素开始
	{
		temp = Arr[i];
		j = i - 1;//已排序中最大的一个
		while (j>=0&&Arr[j]>temp)//当已排序中的最大元素大于数组中的元素的时候
		{
			Arr[j + 1] = Arr[j];//数字交换
			j--;
		}
		Arr[j + 1] = temp;
	}
}
/*
它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
*/
void ShellSort(int Arr[], int size)
{
	int step = size / 2;//步长
	int temp = 0;//定义一个临时变量
	while (step>0)
	{
		for (int i = step; i < size; i++)//插入排序
		{
			temp = Arr[i];
			int j = i - step;
			while (j>=0 && Arr[j]>temp)
			{
				Arr[j + step] = Arr[j];
				j = j - step;
			}
			Arr[j + step] = temp;
		}
		Display(Arr, size);
		step /= 2;
	}
}
/*
计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。
作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
步骤:
找出待排序的数组中最大和最小的元素;
统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。
*/
void CountSort(int Arr[], int size)
{
	int maxNum = Arr[0];
	for (int i = 1; i < size; i++)//找出数组中最大值
	{
		if (Arr[i]>maxNum)
		{
			maxNum = Arr[i];
		}
	}

	int *pTmpArr = new int[maxNum + 1];//创建计数数组,长度为maxNum+1
	memset(pTmpArr, 0x00, sizeof(int)*(maxNum + 1));

	for (int i = 0; i < size; i++)//遍历原数组的元素
	{
		pTmpArr[Arr[i]]++; //对计数数组元素赋值,统计出现的次数
	}

	int index = 0;//下标
	for (int i = 0; i < maxNum; i++)//从最小的数开始计数,遍历计数数组
	{
		for (int j = 0; j < pTmpArr[i]; j++)//将计数数组的索引值填充到数组中
		{
			Arr[index++] = i;
		}
	}
	delete[]pTmpArr;

}
/*
基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,
先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。
*/
void RadixSort(int Arr[], int size)//基数排序
{
	int nBits = NumofBitofArr(Arr, size);//求数组中最大的位数
	int nCount[10] = { 0 };//定义10个桶0~9

	int *pTempArr = new int[size];//定义一个临时数组
	memset(pTempArr, 0x00, sizeof(int)*size);//数组中的元素为0

	int radix = 1;
	for (int i = 0; i <= nBits; i++)//统计循环的次数。。也就是说百位就循环2次,千位就循环3次
	{
		memset(nCount, 0x00, sizeof(nCount));//清空桶
		for (int j = 0; j < size; j++)
		{
			nCount[Arr[j] / radix % 10]++;//取个位、十位.....对应的数字取出来
		}

		// 比如经过计算后 0, 2, 3, 3, 0, 0, 0, 0, 表示0出现了0次,1出现了2次等等,则 0,2, 5, 8, 0, 0, 。。。
		//2表示比较位为1的元素可以存放在索引为1, 0的位置
	    //5表示比较位为2的元素可以存放在4,3,2  3个位置上(5- 2)
		//8表示比较位为3的元素可以存在7,6,5 3个位置上(8 - 5)
		for (int i = 1; i < 10; i++)
		{
			nCount[i] = nCount[i] + nCount[i - 1];
		}

		for (int j = size-1; j >= 0; j--)//在桶中从个位开始,从下到上依次取出
		{
			int k = Arr[j] / radix % 10;
			pTempArr[nCount[k] - 1] = Arr[j];
			nCount[k]--;
		}

		for (int j = 0; j < size; j++)//重新放在桶中
		{
			Arr[j] = pTempArr[j];
		}

		Display(Arr, size);

		radix *= 10;
	}
}

int NumofBitofArr(int iArr[], int size)//求最大的位数
{
	int nBits = 1;//位数
	int temp = 10;
	for (int i = 0; i < size; i++)//遍历数组中每一个数
	{
		while (iArr[i] >= temp)
		{
			temp *= 10;
			nBits++;
		}
	}
	return nBits;
}
/*
从数列中挑出一个元素,称为 “基准”(pivot);
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

*/
void QuickSort(int Arr[], int left, int right)
{
	if (left>=right)
		return;//退出条件

	int Middle = Arr[left];//基准值

	int l = left;//比中间值小的在左边
	int r = right;//比中间值大的在右边

	while (l!=r)
	{
		while (l<r && Arr[r]>=Middle)//首先从数组右边开始扫描,当扫描的值大于等于基准值
			r--;//右边减
		if (l < r)//当小于基准值
			Arr[l] = Arr[r];//就将右边的元素值给左边
		while (l<r && Arr[l]<=Middle) //接着从左边开始扫描,当值小于等于基准值
			l++;//左边加
		if (l<r)
			Arr[r] = Arr[l];//进行数据交换
	}

	Arr[l] = Middle;//将基准值赋予左边

	cout << Middle << "为基准" << endl;
	Display(Arr, 10);

	//采用递归的方式,对于左右2边分别进行快速排序
	QuickSort(Arr, left, l - 1);   //左边
	QuickSort(Arr, l + 1, right);  //右边
}

/*
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
*/
void MergeSort(int Arr[], int size)
{
	int r = size - 1;
	_MergeSort(Arr, 0, r);
}
void _MergeSort(int Arr[], int l,int r)
{
	if (l>=r)
	{
		return;
	}

	int mid = l + (r - l) / 2;//中间值
	_MergeSort(Arr, l, mid);//拆分左边
	_MergeSort(Arr, mid + 1, r);//拆分右边

	mergeArr(Arr, l, mid, r);
}

void mergeArr(int *Arr, int l, int m, int r)
{
	int left = l;//左边
	int right = m+1;//右边第一个元素
	int size = r - l + 1;//2个数组的总长度

	int *tempArr = new int[size];
	int index = 0;//合并数组的开始位置
	while (left<m && right<=r)//这里结束的条件是一个数组已经放进去了
	{
		if (Arr[left]<Arr[right])//开始位置比较,如果左边数组元素小于右边数组,则将左边数组放进去,然后位置加1
		{
			tempArr[index++] = Arr[left++];
		}
		else//否则相反
		{
			tempArr[index++] = Arr[right++];
		}
	}

	while (left<=m)//如果left没有放完就直接放在最后面
	{
		tempArr[index++] = Arr[left++];
	}
	while (right<=r)//如果right没有放完就直接放在最后面
	{
		tempArr[index++] = Arr[right++];
	}
	memcpy(Arr + l, tempArr, sizeof(int)*size);
}



void swap(int& num1, int& num2)
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
}

void Display(int Arr[], int size)
{
	for (int i = 0; i < size; i++)
	{
		cout << Arr[i] << "\t";
	}
	cout << endl;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值