常用排序算法(图解分析)

常用排序算法(图解)

作为一个程序猿,在学习完语言(c,java,python,……)之后,就会接触算法,而算法可大致分为基本算法、加密算法、排序算法、检索算法等等算法。大家接触的第一类算法就是我今天要说的“排序算法”。所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。不稳定排序算法可能会在相等的键值中改变纪录的相对次序,但是稳定排序算法从来不会如此。不稳定排序算法可以被特别地时作为稳定。作这件事情的一个方式是人工扩充键值的比较,如此在其他方面相同键值的两个物件间之比较,就会被决定使用在原先资料次序中的条目,当作一个同分决赛。然而,要记住这种次序通常牵涉到额外的空间负担。


1、排序算法概述

1.1 排序算法分类

常见排序算法可以分为两大类:

非线性时间比较类排序: 通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此称为非线性时间比较类排序。主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等
线性时间非比较类排序: 不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此称为线性时间非比较类排序。 主要有:计数排序,基数排序,桶排序等。

排序算法思维导图

1.2 排序复杂度

排序方法平均时间复杂度最坏时间复杂度最好时间复杂度空间复杂度稳定性备注
插入排序O( n 2 n^2 n2)O( n 2 n^2 n2)O(n)O(1)稳定
希尔排序O(n log ⁡ 2 n \log_2 n log2n)~O( n 2 n^2 n2O( n 2 n^2 n2)O( n 1.3 n^{1.3} n1.3)O(1)不稳定
冒泡排序O( n 2 n^2 n2)O( n 2 n^2 n2)O(n)O(1)稳定
快速排序O(n log ⁡ 2 n \log_2 n log2n)O( n 2 n^2 n2)O(n log ⁡ 2 n \log_2 n log2n)O(n log ⁡ 2 n \log_2 n log2n)不稳定
选择排序O( n 2 n^2 n2)O( n 2 n^2 n2)O( n 2 n^2 n2)O(1)不稳定
堆排序O(n log ⁡ 2 n \log_2 n log2n)O(n log ⁡ 2 n \log_2 n log2n)O(n log ⁡ 2 n \log_2 n log2n)O(1)不稳定
归并排序O(n log ⁡ 2 n \log_2 n log2n)O(n log ⁡ 2 n \log_2 n log2n)O(n log ⁡ 2 n \log_2 n log2n)O(n)稳定
计数排序O(n+k)O(n+k)O(n+k)O(n+k)稳定
基数排序O(n+k)O( n 2 n^2 n2)O(n)O(n+k)稳定
桶排序O(n*k)O(n*k)O(n*k)O(n+k)稳定

1.3 相关概念

**稳定:**如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
**不稳定:**如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
**时间复杂度:**对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
**空间复杂度:**是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。


2、插入排序(Insertion Sort)

插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

2.1 算法描述

一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:

  1. 从第一个元素开始,该元素可以认为已经被排序;
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置后;
  6. 重复步骤2~5。

2.2 动图演示

插入排序

2.3 代码实现

/**
 * 直接插入排序
 * @param arr 需要排序的数组
 */
public static void insertionSort(int[] arr) {
	for(int i = 0; i < arr.length; i ++) {
		int get = arr[i];
		int j = i - 1;
		while(j >= 0 && arr[j] > get) {
			arr[j + 1] = arr[j];
			j--;
		}
		arr[j + 1] = get;
	}
}

3、二分法插入排序(Binary Insert Sort)

二分法插入排序又叫折半插入排序,对半插入排序,二分插入排序,二分法没有排序,只有查找。所以当找到要插入的位置时。移动必须从最后一个记录开始,向后移动一位,再移动倒数第2位,直到要插入的位置的记录移后一位。

3.1 算法描述

  1. 在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们中间的那个元素比,
  2. 如果小,则对前半再进行折半,否则对后半进行折半,直到left<right,
  3. 然后再把第i个元素前1位与目标位置之间的所有元素后移,再把第i个元素放在目标位置上。

3.2 演示图

二分插入排序

3.3 代码实现

	/**
	 * 二分插入排序
	 * @param arr 需要排序的数组
	 */
	public static void insertionSortBinary(int[] arr) { // 已抓牌为例
		for (int i = 1; i < arr.length; i++) {
			int get = arr[i];						// 右手抓到一张扑克牌
			int left = 0;							// 拿在左手上的牌总是排序好的,所以可以用二分法
			int right = i - 1;						// 手牌左右边界进行初始化
			while (left <= right){					// 采用二分法定位新牌的位置
				int mid = (left + right) / 2;
				if (arr[mid] > get) {
					right = mid - 1;
				}else {
					left = mid + 1;
				}
			}
			for (int j = i - 1; j >= left; j--)	{	// 将欲插入新牌位置右边的牌整体向右移动一个单位
				arr[j + 1] = arr[j];
			}
			arr[left] = get; // 将抓到的牌插入手牌
		}
	}

4、希尔排序(Shell Sort)

希尔排序,也叫递减增量排序,是插入排序的一种更高效的改进版本。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序是不稳定的排序算法。

4.1 算法描述

  1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
  2. 按增量序列个数k,对序列进行k 趟排序;
  3. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

4.2 动图演示

希尔排序

4.3 代码实现

	/**
	 * 希尔排序 
	 * @param arr 需要排序的数组
	 */
	public static void shellSort(int arr[]) {
		int h = 0;
		while (h <= arr.length) { 					// 生成初始增量
			h = 3 * h + 1; 							// 动态定义间隔序列
		}
		while (h >= 1) {
			for (int i = h; i < arr.length; i++) {
				int j = i - h;
				int get = arr[i];
				while (j >= 0 && arr[j] > get) {
					arr[j + h] = arr[j];
					j = j - h;
				}
				arr[j + h] = get;
			}
			h = (h - 1) / 3; 						// 递减增量
		}
	}

5、冒泡排序(Bubble Sort)

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

5.1 算法描述

  1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
  3. 针对所有的元素重复以上的步骤,除了最后一个;
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较,排序完成。

5.2 动图演示

冒泡排序

5.3 代码实现

/**
 * 冒泡排序  Bubble Sort
 * @param arr 处理的数组
 */
public static void bubbleSort(int[] arr) {		
	for(int i = 0; i < arr.length - 1; i ++) {
		for(int j = 0; j < arr.length-1-i; j ++) {
			if(arr[j]<arr[j+1]) {// 从大到小 用<, 从小到大 用>
				int temp = 0;
				temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}
		}
	}
}

6、鸡尾酒排序(Cocktail Sort)

鸡尾酒排序,也叫定向冒泡排序,鸡尾酒搅拌排序,搅拌排序(也可以视作选择排序的一种变形),涟漪排序,来回排序或快乐小时排序,是冒泡排序的一种变形。此算法与冒泡排序的不同处在于排序时是以双向在序列中进行排序。此算法与冒泡排序的不同处在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能。

6.1 算法描述

鸡尾酒排序等于是冒泡排序的轻微变形。不同的地方在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能,原因是冒泡排序只从一个方向进行比对(由低到高),每次循环只移动一个项目。
以序列(2,3,4,5,1)为例,鸡尾酒排序只需要访问一次序列就可以完成排序,但如果使用冒泡排序则需要四次。但是在乱数序列的状态下,鸡尾酒排序与冒泡排序的效率都很差劲。

6.2 动图演示

鸡尾酒排序

6.3 代码实现

	/**
	 * 鸡尾酒排序
	 * @param arr
	 */
	public static void cocktailSort(int arr[]) {
		int len = arr.length;
		int i, left = 0, right = len - 1;
		int temp;
		while (left < right) {
			for (i = left; i < right; i++)
				if (arr[i] > arr[i + 1]) {
					temp = arr[i];
					arr[i] = arr[i + 1];
					arr[i + 1] = temp;
				}
			right--;
			for (i = right; i > left; i--)
				if (arr[i - 1] > arr[i]) {
					temp = arr[i];
					arr[i] = arr[i - 1];
					arr[i - 1] = temp;
				}
			left++;
		}
	}

7、快速排序(Quick Sort)

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

7.1 算法描述

  1. 设置两个变量i、j,排序开始的时候:i=0,j=N-1;
  2. 以第一个数组元素作为关键数据,赋值给key,即key=A[0];
  3. 从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]互换;
  4. 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
  5. 重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

7.2 动图演示

快速排序

7.3 代码实现

	/**
	 * 快速排序
	 * 
	 * @param arr
	 *            需要排序的数组
	 * @param _left
	 *            低位
	 * @param _right
	 *            高位
	 */
	public static void quickSort(int arr[], int _left, int _right) {
		int left = _left;
		int right = _right;
		int temp = 0;
		if (left <= right) { // 待排序的元素至少有两个的情况
			temp = arr[left]; // 待排序的第一个元素作为基准元素
			while (left != right) { // 从左右两边交替扫描,直到left = right
				while (right > left && arr[right] >= temp)
					right--; // 从右往左扫描,找到第一个比基准元素小的元素
				arr[left] = arr[right]; // 找到这种元素arr[right]后与arr[left]交换
				while (left < right && arr[left] <= temp)
					left++; // 从左往右扫描,找到第一个比基准元素大的元素
				arr[right] = arr[left]; // 找到这种元素arr[left]后,与arr[right]交换
			}
			arr[right] = temp; // 基准元素归位
			quickSort(arr, _left, left - 1); // 对基准元素左边的元素进行递归排序
			quickSort(arr, right + 1, _right); // 对基准元素右边的进行递归排序
		}
	}

8、选择排序(Selection Sort)

选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。。

8.1 算法描述

n个记录的直接选择排序可经过n-1趟直接选择排序得到有序结果。具体算法描述如下:

  1. 初始状态:无序区为R[1…n],有序区为空;
  2. 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1…i-1]和R(i…n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1…i]和R[i+1…n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
  3. n-1趟结束,数组有序化了。

8.2 动图演示

选择排序

8.3 代码实现

	/**
	 * 选择排序
	 * @param args
	 */
	public static void selectSort(int[] arr) {
		int minIndex = 0;
		int temp = 0;
		if ((arr == null) || (arr.length == 0))
			return;
		for (int i = 0; i < arr.length - 1; i++) {
			minIndex = i;// 无序区的最小数据数组下标
			for (int j = i + 1; j < arr.length; j++) {
				// 在无序区中找到最小数据并保存其数组下标
				if (arr[j] < arr[minIndex]) {
					minIndex = j;
				}
			}
			// 将最小元素放到本次循环的前端
			temp = arr[i];
			arr[i] = arr[minIndex];
			arr[minIndex] = temp;
		}
	}

9、堆排序(Heap Sort)

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

9.1 算法描述

  1. 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
  2. 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
  3. 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

9.2 动图演示

堆排序

9.3 代码实现

	/**
	 * 堆排序
	 * 
	 * @param arr
	 *            需要排序的数组
	 */
	public static void heapSort(int[] arr) {
		// 1.构建大顶堆
		for (int i = arr.length / 2 - 1; i >= 0; i--) {
			// 从第一个非叶子结点从下至上,从右至左调整结构
			adjustHeap(arr, i, arr.length);
		}
		// 2.调整堆结构+交换堆顶元素与末尾元素
		for (int j = arr.length - 1; j > 0; j--) {
			swap(arr, 0, j);// 将堆顶元素与末尾元素进行交换
			adjustHeap(arr, 0, j);// 重新对堆进行调整
		}
	}
	/**
	 * 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
	 * 
	 * @param arr
	 * @param i
	 * @param length
	 */
	public static void adjustHeap(int[] arr, int i, int length) {
		int temp = arr[i];// 先取出当前元素i
		for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {// 从i结点的左子结点开始,也就是2i+1处开始
			if (k + 1 < length && arr[k] < arr[k + 1]) {// 如果左子结点小于右子结点,k指向右子结点
				k++;
			}
			if (arr[k] > temp) {// 如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
				arr[i] = arr[k];
				i = k;
			} else {
				break;
			}
		}
		arr[i] = temp;// 将temp值放到最终的位置
	}
	/**
	 * 交换位置
	 * 
	 * @param arr
	 *            需要交换位置的 数组
	 * @param i
	 *            需要交换位置的 数组的 第一个值的下标
	 * @param j
	 *            需要交换位置的 数组的 第二个值的下标
	 */
	public static void swap(int[] arr, int i, int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}

10、归并排序(Merge Sort)

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2路归并。

10.1 算法描述

  1. 把长度为n的输入序列分成两个长度为n/2的子序列;
  2. 对这两个子序列分别采用归并排序;
  3. 将两个排序好的子序列合并成一个最终的排序序列。

10.2 动图演示

归并排序

10.3 代码实现

	/**
	 * 归并排序
	 * @param arr
	 */
	public static void mergeSort(int []arr){
        int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
        sortMerge(arr,0,arr.length-1,temp);
    }
    private static void sortMerge(int[] arr,int left,int right,int []temp){
        if(left<right){
            int mid = (left+right)/2;
            sortMerge(arr,left,mid,temp);//左边归并排序,使得左子序列有序
            sortMerge(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
            merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
        }
    }
    private static void merge(int[] arr,int left,int mid,int right,int[] temp){
        int i = left;//左序列指针
        int j = mid+1;//右序列指针
        int t = 0;//临时数组指针
        while (i<=mid && j<=right){
            if(arr[i]<=arr[j]){
                temp[t++] = arr[i++];
            }else {
                temp[t++] = arr[j++];
            }
        }
        while(i<=mid){//将左边剩余元素填充进temp中
            temp[t++] = arr[i++];
        }
        while(j<=right){//将右序列剩余元素填充进temp中
            temp[t++] = arr[j++];
        }
        t = 0;
        //将temp中的元素全部拷贝到原数组中
        while(left <= right){
            arr[left++] = temp[t++];
        }
    }

11、计数排序(Counting Sort)

计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

11.1 算法描述

  1. 找出待排序的数组中最大和最小的元素;
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
  3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
  4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

11.2 动图演示

计数排序

11.3 代码实现

	/**
	 * 计数排序
	 * @param arr 需要排序的数组
	 * @param k 数组中的 最大值
	 */
	public static void countingSort(int[] arr, int maxValue) {
		int[] C = new int[maxValue + 1];// 构造C数组
		int length = arr.length, sum = 0;// 获取A数组大小用于构造B数组
		int[] B = new int[length];// 构造B数组
		for (int i = 0; i < length; i++) {
			C[arr[i]] += 1;// 统计A中各元素个数,存入C数组
		}
		for (int i = 0; i < maxValue + 1; i++) {// 修改C数组
			sum += C[i];
			C[i] = sum;
		}
		for (int i = length - 1; i >= 0; i--) {// 遍历A数组,构造B数组
			B[C[arr[i]] - 1] = arr[i];// 将A中该元素放到排序后数组B中指定的位置
			C[arr[i]]--;// 将C中该元素-1,方便存放下一个同样大小的元素

		}
	}

12、桶排序(Bucket Sort)

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

12.1 算法描述

  1. 设置一个定量的数组当作空桶;
  2. 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  3. 对每个不是空的桶进行排序;
  4. 从不是空的桶里把排好序的数据拼接起来。

12.2 演示图

桶排序

12.3 代码实现

	/**
	 * 桶排序 
	 * @param arr 需要排序的数组
	 * @param bucketCount 桶大小
	 */
	public static void bucketSort(Integer arr[], int bucketCount) {
		int len = arr.length;
		double[] result = new double[len];
		double min = arr[0];
		double max = arr[0];
		// 找到最大值和最小值
		for (int i = 1; i < len; i++) {
			min = min <= arr[i] ? min : arr[i];
			max = max >= arr[i] ? max : arr[i];
		}
		// 求出每一个桶的数值范围
		double space = (max - min + 1) / bucketCount;
		// 先创建好每一个桶的空间,这里使用了泛型数组
		ArrayList<Integer>[] arrList = new ArrayList[bucketCount];
		// 把arr中的数均匀的的分布到[0,1)上,每个桶是一个list,存放落在此桶上的元素
		for (int i = 0; i < len; i++) {
			int index = (int) Math.floor((arr[i] - min) / space);
			if (arrList[index] == null) {
				// 如果链表里没有东西
				arrList[index] = new ArrayList<Integer>();
				arrList[index].add(arr[i]);
			} else {
				// 排序
				int k = arrList[index].size() - 1;
				while (k >= 0 && (Integer) arrList[index].get(k) > arr[i]) {
					if (k + 1 > arrList[index].size() - 1) {
						arrList[index].add(arrList[index].get(k));
					} else {
						arrList[index].set(k + 1, arrList[index].get(k));
					}
					k--;
				}
				if (k + 1 > arrList[index].size() - 1) {
					arrList[index].add(arr[i]);
				} else {
					arrList[index].set(k + 1, arr[i]);
				}
			}
		}
		// 把各个桶的排序结果合并 ,count是当前的数组下标
		int count = 0;
		for (int i = 0; i < bucketCount; i++) {
			if (null != arrList[i] && arrList[i].size() > 0) {
				Iterator<Integer> iter = arrList[i].iterator();
				while (iter.hasNext()) {
					Integer d = (Integer) iter.next();
					result[count] = d;
					count++;
				}
			}
		}
	}

13、基数排序(Radix Sort)

基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

13.1 算法描述

  1. 取得数组中的最大数,并取得位数;
  2. arr为原始数组,从最低位开始取每个位组成radix数组;
  3. 对radix进行计数排序(利用计数排序适用于小范围数的特点);

13.2 动图演示

基数排序

13.3 代码实现

	/** 
	  * 基数排序
      * @param array 待排序数组 
      * @param radix 基数(10,盒子个数) 
      * @param distanced 待排序中,最大的位数 
      * */  
    private static void radixSort(int[] array,int radix, int distance) {    
        int length = array.length;    
        int[] temp = new int[length];//用于暂存元素    
        int[] count = new int[radix];//用于计数排序  盒子  每一位的个  
        int divide = 1;    
            
        for (int i = 0; i < distance; i++) {    
            System.arraycopy(array, 0,temp, 0, length);    
            Arrays.fill(count, 0);//盒子清空    
            for (int j = 0; j < length; j++) {//这个循环用来把每个数的个十百千位分开,并且使相对应号数的桶的个数增加1  
                //divide : 1 10 100  
                //radix : 基数 10  
                int tempKey = (temp[j]/divide) % radix;  //temp[j]/divide  每一位的个  
                count[tempKey]++;  //每一位的个  
            }    
            //radix : 基数 10    
            for (int j = 1; j < radix; j++) {    
                count [j] = count[j] + count[j-1];    
            }    
            //个人觉的运用 数排序实现计数排序的重点在下面这个方法                
            for (int j = length - 1; j >= 0; j--) {    
                int tempKey = (temp[j]/divide)%radix;    
                count[tempKey]--;    
                array[count[tempKey]] = temp[j];    
            }    
            divide = divide * radix; // 1 10 100                    
        }    
    }  

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漏墨小子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值