【✈️️️排序算法,一文讲尽!Top 10 Sort Algorithms✈️️️】C/C++ 实现经典十大排序算法

107 阅读3分钟

废话不多说,直接上代码!

Talk is cheap.Show me the code.

#include <iostream>
#include <string>
#include "stdio.h"

using namespace std;

void PrintArr(string  str,int arr[], int len ,bool bisSorted = true)
{
	cout << str;

	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
}

//交换数值
//统一封装接口
void  SwapValue(int &a, int &b)
{
	int tmp = 0;

	tmp = a;
	a = b;
	b = tmp;
}

//冒泡排序
void BubbleSort(int arr[], int len)
{
	int i, j = 0;
	for (i = 0;i< len -1;i++)
	{
		for (j = 0;j < len -1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				SwapValue(arr[j], arr[j + 1]);
			}
		}
	}
}

//插入排序
void InsertionSort(int arr[],int len)
{
	int i, j= 0;

	//在要排序的一组数中,假定前n-1个数已经排好序,现将第n个数插到前面的有序数列中,
	//使得这n个数也是排好顺序的。如此反复循环,直到全部排好顺序。
	for (i = 0; i < len - 1; i++)
	{
		for (j = i + 1; j > 0; j--)
		{
			if (arr[j] < arr[j - 1])
			{
				SwapValue(arr[j],arr[j - 1]);
			}
			else
			{
				break;
			}
		}
	}
}

//希尔排序
void ShellSort(int a[], int len)
{
	int i, j, k, tmp, gap;  // gap 为步长
	for (gap = len / 2; gap > 0; gap /= 2) {  // 步长初始化为数组长度的一半,每次遍历后步长减半,
		for (i = 0; i < gap; ++i) { // 变量 i 为每次分组的第一个元素下标 
			for (j = i + gap; j < len; j += gap) { //对步长为gap的元素进行直插排序,当gap为1时,就是直插排序
				tmp = a[j];  // 备份a[i]的值
				k = j - gap;  // j初始化为i的前一个元素(与i相差gap长度)

				while (k >= 0 && a[k] > tmp) {
					a[k + gap] = a[k]; // 将在a[i]前且比tmp的值大的元素向后移动一位
					k -= gap;
				}

				a[k + gap] = tmp;
			}
		}
	}
}

//快速排序
void QuickSort(int *a, int left, int right)
{
	if (left >= right)/*如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了*/
	{
		return;
	}
	int i = left;
	int j = right;
	int key = a[left];

	while (i < j)                               /*控制在当组内寻找一遍*/
	{
		while (i < j && key <= a[j])
			/*而寻找结束的条件就是,1,找到一个小于或者大于key的数(大于或小于取决于你想升
			序还是降序)2,没有符合条件1的,并且i与j的大小没有反转*/
		{
			j--;/*向前寻找*/
		}

		a[i] = a[j];
		/*找到一个这样的数后就把它赋给前面的被拿走的i的值(如果第一次循环且key是
		a[left],那么就是给key)*/

		while (i < j && key >= a[i])
			/*这是i在当组内向前寻找,同上,不过注意与key的大小关系停止循环和上面相反,
			因为排序思想是把数往两边扔,所以左右两边的数大小与key的关系相反*/
		{
			i++;
		}

		a[j] = a[i];
	}

	a[i] = key;/*当在当组内找完一遍以后就把中间数key回归*/
	QuickSort(a, left, i - 1);/*最后用同样的方式对分出来的左边的小组进行同上的做法*/
	QuickSort(a, i + 1, right);/*用同样的方式对分出来的右边的小组进行同上的做法*/
					   /*当然最后可能会出现很多分左右,直到每一组的i = j 为止*/
}

//选择排序
void SelectionSort(int arr[], int len)
{
	int i, j = 0;

	for (i = 0; i < len - 1; i++)
	{
		int min = i;
		for (j = i + 1; j < len; j++)     //走访未排序的元素
		{
			if (arr[j] < arr[min])    //找到目前最小值
			{
				min = j;    //记录最小值
			}
		}

		//做交换
		SwapValue(arr[min], arr[i]);
	}
}

//计数排序
void CountSort(int data[], int n)
{
	int i, j, count, *data_p, temp;

	data_p = (int*)malloc(sizeof(int)*n);
	for (i = 0; i < n; i++)//初始化data_p
	{
		data_p[i] = 0;
	}

	for (i = 0; i < n; i++)
	{
		count = 0;
		for (j = 0; j < n; j++)//扫描待排序数组
		{
			if (data[j] < data[i])//统计比data[i]值小的值的个数
			{
				count++;
			}
		}
		
		while (data_p[count] != 0)//对于相等非0的数据,应向后措一位。数据为0时,因数组data_p被初始化为0,故不受影响。
		{
			/* 注意此处应使用while循环进行判断,若用if条件则超过三个重复值后有0出现 */
			count++;
		}

		data_p[count] = data[i];//存放到data_p中的对应位置
	}

	//用于检查当有多个数相同时的情况
	i = 0, j = n;

	while (i < j)
	{
		if (data_p[i] == 0)
		{
			temp = i - 1;
			data_p[i] = data_p[temp];
		}//of if

		i++;
	}//of  while

	for (i = 0; i < n; i++)//把排序完的数据复制到data中
	{
		data[i] = data_p[i];
	}

	free(data_p);//释放data_p
}

/*
 * 桶排序
 *
 * 参数说明:
 *   a -- 待排序数组
 *   n -- 数组a的长度
 *   max -- 数组a中最大值的范围
 */
void BucketSort(int a[], int n, int max)
{
	int i, j;
	int *buckets;

	if (a == NULL || n < 1 || max < 1)
		return;

	// 创建一个容量为max的数组buckets,并且将buckets中的所有数据都初始化为0。
	if ((buckets = (int *)malloc(max * sizeof(int))) == NULL)
		return;
	memset(buckets, 0, max * sizeof(int));

	// 1. 计数
	for (i = 0; i < n; i++)
		buckets[a[i]]++;

	// 2. 排序
	for (i = 0, j = 0; i < max; i++)
		while ((buckets[i]--) > 0)
			a[j++] = i;

	free(buckets);
}


// 递归的方式实现归并排序
#define MAXSIZE 10
// 实现归并,并把结果存放到list1
void merging(int *list1, int list1_size, int *list2, int list2_size)
{
	int i, j, k, m;
	int temp[MAXSIZE];

	i = j = k = 0;

	while (i < list1_size && j < list2_size)
	{
		if (list1[i] < list2[j])
		{
			temp[k] = list1[i];
			k++;
			i++;
		}
		else
		{
			temp[k++] = list2[j++];
		}
	}

	while (i < list1_size)
	{
		temp[k++] = list1[i++];
	}

	while (j < list2_size)
	{
		temp[k++] = list2[j++];
	}

	for (m = 0; m < (list1_size + list2_size); m++)
	{
		list1[m] = temp[m];
	}
}

//归并排序
void MergeSort(int k[], int n)
{
	if (n > 1)
	{
		/*
		*list1是左半部分,list2是右半部分
		*/
		int *list1 = k;
		int list1_size = n / 2;
		int *list2 = k + list1_size;
		int list2_size = n - list1_size;

		MergeSort(list1, list1_size);
		MergeSort(list2, list2_size);

		// 把两个合在一起
		merging(list1, list1_size, list2, list2_size);
	}
}


//基数排序
int maxbit(int data[], int n) //辅助函数,求数据的最大位数
{
	int maxData = data[0];              ///< 最大数
	/// 先求出最大数,再求其位数,这样有原先依次每个数判断其位数,稍微优化点。
	for (int i = 1; i < n; ++i)
	{
		if (maxData < data[i])
			maxData = data[i];
	}
	int d = 1;
	int p = 10;
	while (maxData >= p)
	{
		//p *= 10; // Maybe overflow
		maxData /= 10;
		++d;
	}
	return d;
	/*    int d = 1; //保存最大的位数
		int p = 10;
		for(int i = 0; i < n; ++i)
		{
			while(data[i] >= p)
			{
				p *= 10;
				++d;
			}
		}
		return d;*/
}
void RadixSort(int data[], int n)
{
	int d = maxbit(data, n);
	int *tmp = new int[n];
	int *count = new int[10]; //计数器
	int i, j, k;
	int radix = 1;
	for (i = 1; i <= d; i++) //进行d次排序
	{
		for (j = 0; j < 10; j++)
			count[j] = 0; //每次分配前清空计数器
		for (j = 0; j < n; j++)
		{
			k = (data[j] / radix) % 10; //统计每个桶中的记录数
			count[k]++;
		}
		for (j = 1; j < 10; j++)
			count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
		for (j = n - 1; j >= 0; j--) //将所有桶中记录依次收集到tmp中
		{
			k = (data[j] / radix) % 10;
			tmp[count[k] - 1] = data[j];
			count[k]--;
		}
		for (j = 0; j < n; j++) //将临时数组的内容复制到data中
			data[j] = tmp[j];
		radix = radix * 10;
	}
	delete[]tmp;
	delete[]count;
}


//堆排序
void max_heapify(int arr[], int start, int end) {
	//建立父节点下标和子节点下标
	int dad = start;
	int son = dad * 2 + 1;
	while (son <= end) { // 若子节点下标在范围内才做比较
		if (son + 1 <= end && arr[son] < arr[son + 1]) { // 先比较两个子节点大小,选择最大的
			son++;
		}

		if (arr[dad] > arr[son]) {// 如果父节点大于子节点代表调整完毕,直接跳出函数
			return;
		}
		else { // 否则交换父子内容再继续子节点和孙节点比较
			SwapValue(arr[dad], arr[son]);
			dad = son;
			son = dad * 2 + 1;
		}
	}
}

void HeapSort(int arr[], int len) {
	int i;
	// 初始化,i从最后一个父节点开始调整
	for (i = len / 2 - 1; i >= 0; i--) {
		max_heapify(arr, i, len - 1);
	}

	// 先将第一个元素和已排好元素前一位做交换,然后再重新调整,直到排序完毕
	for (i = len - 1; i > 0; i--) {
		SwapValue(arr[0], arr[i]);
		max_heapify(arr, 0, i - 1);
	}
}


int main()
{
	cout << "Sort Collection\n";

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr1[] = {2, 4, 6, 5, 8, 1,3,7};
	int len1 = (int) sizeof(arr1) / sizeof(arr1[0]);
	PrintArr("arr  original:", arr1, len1);
	BubbleSort(arr1, len1);
	PrintArr("arr Bubble-Sort :", arr1, len1);

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr2[] = { 2, 4, 6, 5, 8, 1,3,7 };
	int len2 = (int) sizeof(arr2) / sizeof(arr2[0]);
	PrintArr("arr  original:", arr2, len2);
	InsertionSort(arr2, len2);
	PrintArr("arr Insertion-Sort :", arr2, len2);

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr3[] = { 2, 4, 6, 5, 8, 1,3,7 };
	int len3 = (int) sizeof(arr3) / sizeof(arr3[0]);
	PrintArr("arr  original:", arr3, len3);
	ShellSort(arr3, len3);
	PrintArr("arr Shell's-Sort :", arr3, len3);

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr4[] = { 2, 4, 6, 5, 8, 1,3,7 };
	int len4 = (int) sizeof(arr4) / sizeof(arr4[0]);
	PrintArr("arr  original:", arr4, len4);
	QuickSort(arr4, 0, len4-1);
	PrintArr("arr Quick-Sort:", arr4, len4);

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr5[] = { 2, 4, 6, 5, 8, 1,3,7 };
	int len5 = (int) sizeof(arr5) / sizeof(arr5[0]);
	PrintArr("arr  original:", arr5, len5);
	SelectionSort(arr5, len5);
	PrintArr("arr Selection-Sort :", arr5, len5);

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr6[] = { 2, 4, 6, 5, 8, 1,3,7 };
	int len6 = (int) sizeof(arr6) / sizeof(arr6[0]);
	PrintArr("arr  original:", arr6, len6);
	CountSort(arr6, len6);
	PrintArr("arr Count-Sort :", arr6, len6);

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr7[] = { 2, 4, 6, 5, 8, 1,3,7 };
	int len7 = (int) sizeof(arr7) / sizeof(arr7[0]);
	PrintArr("arr  original:", arr7, len7);
	BucketSort(arr7, len7, 10);
	PrintArr("arr Bucket-Sort :", arr7, len7);

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr8[] = { 2, 4, 6, 5, 8, 1,3,7 };
	int len8 = (int) sizeof(arr8) / sizeof(arr8[0]);
	PrintArr("arr  original:", arr8, len8);
	MergeSort(arr8, len8);
	PrintArr("arr Merge-Sort :", arr8, len8);

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr9[] = { 2, 4, 6, 5, 8, 1,3,7 };
	int len9 = (int) sizeof(arr9) / sizeof(arr9[0]);
	PrintArr("arr  original:", arr9, len9);
	RadixSort(arr9, len9);
	PrintArr("arr Radix-Sort :", arr9, len9);

	/****************************************************/
	cout << "\n------------------------------------------------\n";
	int arr10[] = { 2, 4, 6, 5, 8, 1,3,7 };
	int len10 = (int) sizeof(arr10) / sizeof(arr10[0]);
	PrintArr("arr  original:", arr10, len10);
	RadixSort(arr10, len10);
	PrintArr("arr Heap-Sort :", arr10, len10);

	system("pause");
	return 0;
}

\