这里可以附上一个模拟排序算法的网址 http://www.atool9.com/sort.php
内部排序算法

一.交换排序

1.冒泡排序

/*
 * 它重复地走访过要排序的数列,
 * 一次比较两个元素,如果他们的顺序错误就把他们交换过来。
 * 走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
 */
 public:
	static void bubbleSort(int array[], int length) {
		for (int i = 0; i < length - 1; i++) {				//确定排序次数
			for (int j = 0; j < length - i - 1; j++) {		//确定比较次数
				if (array[j] > array[j + 1]) {
					int temp = array[j + 1];				//交换
					array[j] = array[j + 1];
					array[j + 1] = temp;
				}
			}
		}
	}

(1)冒泡排序优化

/*
 * 假设我们现在排序ar[]={1,2,3,4,5,6,7,8,10,9}这组数据,
 * 按照上面的排序方式,第一趟排序后将10和9交换已经有序,接下来的8趟排序就是多余的,什么也没做。
 * 所以我们可以在交换的地方加一个标记,
 * 如果那一趟排序没有交换元素,说明这组数据已经有序,不用再继续下去。
 */
 public:
	static void bubbleSort_1(int array[], int length) {
		for (int i = 0; i < length - 1; i++) {		  //确定排序次数
			bool hasSwaped = false;
			for (int j = 0; j < length - i - 1; j++) {//确定比较次数
				if (array[j] > array[j + 1]) {
					int temp = array[j];			  //交换
					array[j] = array[j + 1];
					array[j + 1] = key;
					hasSwaped = temp;				  //标记已交换
				}
			}
			if (!hasSwaped) {						  //如果没有发生过交换,则已经有序
				break;
			}
		}
	}

(2)冒泡排序优化

/*
 * 我们可以记下最后一次交换的位置,
 * 后边没有交换,必然是有序的,
 * 然后下一次排序从第一个比较到上次记录的位置结束即可。
 */
 public:
	static void bubbleSort_2(int array[], int length) {
		int k = length - 1;
		for (int i = 0; i < length - 1; i++) {
			int lastIndex = 0;					//用来记录最后一次交换的位置
			bool hasSwaped = false;
			for (int j = 0; j < k; j++) {		//确定排序次数
				if (array[j] > array[j + 1]) {	//确定排序次数
					int temp = array[j];
					array[j] = array[j + 1];
					array[j + 1] = temp;
					lastIndex = j;				//交换元素,记录最后一次交换的位置
					hasSwaped = true;			//标记已交换
				}
			}
			if (!hasSwaped) {
				break;
			}
			k = lastIndex;						//下一次比较上一次最后交换的位置即可
		}
	}

2.快速排序

/*
 * 快速排序(Quicksort)是对冒泡排序的一种改进。
 * 它的基本思想是:
 * 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有   数据都要小,
 * 然后再按此方法对这两部分数据分别进行快速排序,
 * 整个排序过程可以递归进行,以此达到整个数据变成有序序列。
 */
public:
	static void quickSort(int array[], int length) {		//使封装更加易用
		doQuick(array, 0, length - 1);
	}

	//递归
public:
	static void doQuick(int array[], int left, int right) {
		int par = partion(array, left, right);
		if (left >= right) {								//递归出口
			return;
		} else {
			doQuick(array, left, right - 1);				//对前半段进行快速排序	
			doQuick(array, left + 1, right);				//对后半段进行快速排序
		}
	}

	//返回基准位置
public:
	static int partion(int array[], int left, int right) {
		int key = array[left];								//默认取第一个元素作为基准元
		while (left < right) {
			while (left < right && array[right] >= key) {
				right--;
			}
			array[left] = array[right];

			while (left < right && array[left] <= key) {
				left++;
			}
			array[right] = array[left];
		}
		array[left] = key;									//基准元居中
		return left;
	}

(1)快速排序(非递归)

其中的partion()函数还是上面的,且需要引入头文件 stack

/*
 * 递归的算法主要是在划分子区间,如果要非递归实现快排,只要使用一个栈来保存区间就可以了。
 * 一般将递归程序改成非递归首先想到的就是使用栈,因为递归本身就是一个压栈的过程。
 */
public:
	static void quickSort1(int array[], int length) {
		stack<int> stack;
		stack.push(0);
		stack.push(length - 1);							//后入的right端点,所以要先拿right
		while (!stack.empty()) {
			int right = stack.top();					//right端点在栈顶
			stack.pop();
			int left = stack.top();
			stack.pop();

			int index = partion(array, left, right);
			if (index - 1 > left) {						//左子序列
				stack.push(left);		
				stack.push(index - 1);
			}
			if (index + 1 < right) {					//右子序列
				stack.push(index + 1);
				stack.push(right);
			}
		}
	}

二.插入排序

1.直接插入排序

/*
 * 插入排序的基本思想是:
 * 每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入 完为止。
 */
 public:
	static void insertSort(int array[], int length) {
		for (int i = 0; i < length; i++) {
			if (array[i] < array[i - 1]) {
				int temp = array[i];
				int j = 0;
				for (int j = i - 1; j >= 0 && temp < array[j]; j--) {
					array[j + 1] = array[j];
				}
				array[j + 1] = temp;
			}
		}
	}

三.选择排序

1.简单选择排序

/*
 * 它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,
 * 存放在序列的起始位置,直到全部待排序的数据元素排完。
 * 选择排序是不稳定的排序方法。
 */
 public:
	static void selectSort(int array[], int length) {
		for (int i = 0; i < length; i++) {
			int index = i;
			for (int j = i + 1; j < length; j++) {
				if (array[j] < array[index]) {
					index = j;
				}
			}
			if (index != i) {
				int temp = array[index];
				array[index] = array[i];
				array[i] = temp;
			}
		}
	}

四.归并排序

/*
 * 归并排序是建立在归并操作上的一种有效的排序算法,
 * 该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
 * 将已有序的子序列合并,得到完全有序的序列;
 * 即先使每个子序列有序,再使子序列段间有序。
 * 若将两个有序表合并成一个有序表,称为二路归并。
 */
public:
	static void mergeSort(int array[], int length) {
		int* temp = new int[length];
		mergeSort(array, 0,length - 1, temp);
	}
public:
	static void mergeSort(int array[], int left, int right, int temp[]) {
		if(left < right) {
			int mid = (left + right) / 2;
			mergeSort(array, left, mid, temp);			//对左子数组进行归并排序
			mergeSort(array, mid + 1, right, temp);		//对右子数组进行归并排序
			merge(array, left, mid, right, temp);		//将数组进行排序
		}
	}
public:
	static void merge(int array[], int left, int mid, int right, int temp[]) {
		int i = left;
		int j = mid + 1;
		int t = 0;										//辅助数组的下标
		while (i <= mid && j <= right) {
			//当二者都没有到达最后一位时,进行比较并向辅助数组复制
			if (array[i] < array[j]) {
				temp[t++] = array[i++];
			} else {
				temp[t++] = array[j++];
			}
		}
		//当其中一个数组复制完毕后,将另一个数组内的数组全部复制到辅助辅助
		while (i <= mid) {
			temp[t++] = array[i++];
		}
		while (j <= right) {
			temp[t++] = array[j++];
		}
		t = 0;
		while (left <= right) {
			array[left++] = temp[t++];
		}
	}

五.基数排序

这里用到了vector来模拟二维数组,需要引入头文件vector

/*
 * 基数排序(Radix Sort)是桶排序的扩展。
 * 它的基本思想是:将整数按位数切割成不同的数字,然后按每个位数分别比较。
 * 具体做法是:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。
 * 然后,从最低位开始,依次进行一次排序。
 * 这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。
 */
//辅助函数, 求数据的最大位数
public:
	static int maxBit(int array[], int length) {
		int maxBit = 0;
		for (int i = 0; i < length; i++) {
			int bit = 1;
			int temp = array[i];
			while (temp / 10 != 0) {				//计算每个数的位数存在count中
				temp = temp / 10;
				bit++;
			}
			maxBit = (bit > maxBit) ? bit : maxBit;	//将最大数复制给maxBit;
		}
		return maxBit;
	}

public:
	static void radixSort(int array[], int length) {
		int bit = maxBit(array, length);					//取得最大位数
		int radix = 1;
		for (int i = 0; i < bit; i++) {						//位数决定排序循环次数
			int count[10];									//计数器count为了统计每个桶放了几个数
			for (int j = 0; j < 10; j++) {					//每次初始化计数器
				count[j] = 0;
			}
			//这里用到vector来模拟二维数组
			vector<vector<int>>	temp;						//temp相当于桶,前一个数标记第几个篮子,后一个为了标记放的个数
			for (int j = 0; j < 10; j++) {					//每次都初始化桶
				vector<int> temp2(length, 10);
				temp.push_back(temp2);
			}
			for (int j = 0; j < length; j++) {
				int k = (array[j] / radix) % 10;
				temp[k][count[k]] = array[j];				//把数据放k桶的te位上存储
				count[k]++;
			}
			int b = 0;
			for (int j = 0; j < 10; j++) {
				if (count[j] > 0) {							//j>0说明j桶内有数字存储
					for (int k = 0; k < count[j]; k++) {	//count[j]是j桶的存储个数
						array[b] = temp[j][k];				//把桶内排好的数全都倒给要排序的数组,进行下轮排序
						b++;
					}
				}
			}
			radix = radix * 10;
		}
	}

这里附上一个基数排序过程图解 https://www.cnblogs.com/skywang12345/p/3603669.html

相关文章: