声明

1)该文章整理自网上的大牛和专家无私奉献的资料,具体引用的资料请看参考文献。
2)本文仅供学术交流,非商用。如果某部分不小心侵犯了大家的利益,还望海涵,并联系博主删除。
3)博主才疏学浅,文中如有不当之处,请各位指出,共同进步,谢谢。
4)此属于第一版本,若有错误,还需继续修正与增删。还望大家多多指点。大家都共享一点点,一起为祖国科研的推进添砖加瓦。

文章目录

  • 声明
    • 0、写在前面
    • 1、冒泡排序
    • 2、选择排序
    • 3、插入排序
    • 4、希尔排序
    • 5、归并排序
    • 6、快速排序
    • 7、堆排序
    • 8、计数排序
    • 9、桶排序
    • 10、基数排序
    • 参考

0、写在前面

最近终于是学到了排序算法,

排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。

为什么排序算法在很多领域被相当地重视?

主要是一个优秀的算法可以节省大量的资源,尤其是在大量数据的处理方面。

排序算法可以分为内部排序和外部排序:

  • 内部排序是数据记录在内存中进行排序,
  • 而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。

经典排序算法主要有一下几个(思维导图):

点击查看大图!

主要的性质肯定少不了:

  • 数据对象

数据对象
数组或者链表,或者both。

  • 稳定性

稳定性
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且 r[i]r[j] 之前,而在排序后的序列中,r[i] 仍在 r[j] 之前,则称这种排序算法是 稳定 的;否则称为 不稳定 的。

  • 时间复杂度

时间复杂度
时间复杂性,又称时间复杂度,是一个定性描述该算法的运行时间的函数。

  • 空间复杂度

空间复杂度
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。

点击查看大图!

1、冒泡排序

描述:

重复地走访要排序的元素列,依次比较两个相邻的元素,如果顺序错误,就把他们交换。

动图演示:

  • 什么时候最快?
    当输入的数据已经是正序时(???那还用排序?都已经是正序了,还要你何用)。
  • 什么时候最慢?
    当输入的数据是反序时(死心眼嘛?循环反序再输出数据不就行了,还用你是闲的吗)。

代码:

#python
def bubbleSort(arr):for i in range(1, len(arr)):for j in range(0, len(arr)-i):if arr[j] > arr[j+1]:arr[j], arr[j + 1] = arr[j + 1], arr[j]return arr
//C
void swap(int *a,int *b){int temp = *a;*a = *b;*b = temp;
}
void bubble_sort(int arr[], int len){int i, j, temp;for (i = 0; i < len - 1; i++)for (j = 0; j < len - 1 - i; j++)if (arr[j] > arr[j + 1]) {swap(&arr[j], &arr[j + 1]);}
}
//C++
template<typename T>
void bubble_sort(T arr[], int len) {int i, j;for (i = 0; i < len - 1; i++)for (j = 0; j < len - 1 - i; j++)if (arr[j] > arr[j + 1])swap(arr[j], arr[j + 1]);
}

写一个 Swap 交换和 flag 提前跳出,加上第一层倒序循环,是可以的。


参考MOOC浙大数据结构

// C
void Swap(ElementType *a, ElementType *b){ElementType t = *a; *a = *b; *b = t;
}
void BubbleSort(ElementType A[], int N){int P, i;int flag;for (P = N - 1; P >= 0; P--){flag = 0;for (i = 0; i < P; i++){if (A[i] > A[i + 1]){Swap(&A[i], &A[i + 1]);flag = 1;}}if (flag = 0) break;}
}

2、选择排序

描述:

第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。

动图演示:

(其实就是打牌,抓牌,看牌,马牌)

代码:

#python
def selectionSort(arr):for i in range(len(arr) - 1):# 记录最小数的索引minIndex = ifor j in range(i + 1, len(arr)):if arr[j] < arr[minIndex]:minIndex = j# i 不是最小数时,将 i 和最小数进行交换if i != minIndex:arr[i], arr[minIndex] = arr[minIndex], arr[i]return arr
//C
void swap(int *a,int *b){int temp = *a;*a = *b;*b = temp;
}
void selection_sort(int arr[], int len){int i,j;for (i = 0 ; i < len - 1 ; i++){int min = i;//遍历未排序的元素for (j = i + 1; j < len; j++){if (arr[j] < arr[min])     //找到目前最小值min = j;              //记录最小值swap(&arr[min], &arr[i]);   //做交換}}
}
//C++
template<typename T>
void selection_sort(std::vector<T>& arr) {for (int i = 0; i < arr.size() - 1; i++) {int min = i;for (int j = i + 1; j < arr.size(); j++){if (arr[j] < arr[min])min = j;std::swap(arr[i], arr[min]);}}
}

参考MOOC浙大数据结构

// C
void Swap(ElementType *a, ElementType *b){ElementType t = *a; *a = *b; *b = t;
}
void SimpleSelectionSort(ElementType A[], int N){int i, j, min;for (i = 0; i < N-1; i++){min = i;for (j = i + 1; j < N; j++){if (A[i] < A[min])min = j;Swap(&A[i], &A[min]);}}
}

3、插入排序

描述:

通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

动图演示:

(慢,真的慢,不是假的)

代码:

#python
def insertionSort(arr):for i in range(len(arr)):preIndex = i-1current = arr[i]while preIndex >= 0 and arr[preIndex] > current:arr[preIndex+1] = arr[preIndex]preIndex-=1arr[preIndex+1] = currentreturn arr
//C
void insertion_sort(int arr[], int len){int i,j,key;for (i=1;i<len;i++){key = arr[i];j=i-1;while((j>=0) && (arr[j]>key)) {arr[j+1] = arr[j];j--;}arr[j+1] = key;}
}
//C++
void insertion_sort(int arr[],int len){for(int i=1;i<len;i++){int key=arr[i];int j=i-1;while((j>=0) && (key<arr[j])){arr[j+1]=arr[j];j--;}arr[j+1]=key;}
}

参考MOOC浙大数据结构

void InsertionSort( ElementType A[], int N ){int P, i;ElementType Tmp;for ( P=1; P<N; P++ ) {Tmp = A[P];for ( i=P; i>0 && A[i-1]>Tmp; i-- )A[i] = A[i-1];A[i] = Tmp;}
}

4、希尔排序

描述:

把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

动图演示:

希尔排序是基于插入排序进行改进的,(改完确实快了好多啊,以前是老黄牛,现在是小摩托了)

代码:

#python
def shellSort(arr):import mathgap=1while(gap < len(arr)/3):gap = gap*3+1while gap > 0:for i in range(gap,len(arr)):temp = arr[i]j = i-gapwhile j >=0 and arr[j] > temp:arr[j+gap]=arr[j]j-=gaparr[j+gap] = tempgap = math.floor(gap/3)return arr
//C
void shell_sort(int arr[], int len) {int gap, i, j;int temp;for (gap = len >> 1; gap > 0; gap >>= 1){for (i = gap; i < len; i++) {temp = arr[i];for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap)arr[j + gap] = arr[j];arr[j + gap] = temp;}}
}
//C++
template<typename T>
void shell_sort(T array[], int length) {int h = 1;while (h < length / 3) {h = 3 * h + 1;}while (h >= 1) {for (int i = h; i < length; i++) {for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {std::swap(array[j], array[j - h]);}}h = h / 3;}
}

参考MOOC浙大数据结构

void ShellSort( ElementType A[], int N ){int Si, D, P, i;ElementType Tmp;/* 这里只列出一小部分增量 */int Sedgewick[] = {929, 505, 209, 109, 41, 19, 5, 1, 0};for ( Si=0; Sedgewick[Si]>=N; Si++ ) ;for ( D=Sedgewick[Si]; D>0; D=Sedgewick[++Si] ){for ( P=D; P<N; P++ ){Tmp = A[P];for ( i=P; i>=D && A[i-D]>Tmp; i-=D )A[i] = A[i-D];A[i] = Tmp;}}
}

5、归并排序

描述:

采用分而治之法的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

动图演示:

就是化整为零,分家,哈哈

代码:

#python
def mergeSort(arr):import mathif(len(arr)<2):return arrmiddle = math.floor(len(arr)/2)left, right = arr[0:middle], arr[middle:]return merge(mergeSort(left), mergeSort(right))def merge(left,right):result = []while left and right:if left[0] <= right[0]:result.append(left.pop(0))else:result.append(right.pop(0));while left:result.append(left.pop(0))while right:result.append(right.pop(0));return result
//C
void merge_sort_recursive(int arr[], int reg[], int start, int end) {if (start >= end)return;int len = end - start, mid = (len >> 1) + start;int start1 = start, end1 = mid;int start2 = mid + 1, end2 = end;merge_sort_recursive(arr, reg, start1, end1);merge_sort_recursive(arr, reg, start2, end2);int k = start;while (start1 <= end1 && start2 <= end2)reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];while (start1 <= end1)reg[k++] = arr[start1++];while (start2 <= end2)reg[k++] = arr[start2++];for (k = start; k <= end; k++)arr[k] = reg[k];
}
void merge_sort(int arr[], const int len) {int reg[len];merge_sort_recursive(arr, reg, 0, len - 1);
}
//C++
void Merge(vector<int> &Array, int front, int mid, int end) {// preconditions:// Array[front...mid] is sorted// Array[mid+1 ... end] is sorted// Copy Array[front ... mid] to LeftSubArray// Copy Array[mid+1 ... end] to RightSubArrayvector<int> LeftSubArray(Array.begin() + front, Array.begin() + mid + 1);vector<int> RightSubArray(Array.begin() + mid + 1, Array.begin() + end + 1);int idxLeft = 0, idxRight = 0;LeftSubArray.insert(LeftSubArray.end(), numeric_limits<int>::max());RightSubArray.insert(RightSubArray.end(), numeric_limits<int>::max());// Pick min of LeftSubArray[idxLeft] and RightSubArray[idxRight], // and put into Array[i]for (int i = front; i <= end; i++) {if (LeftSubArray[idxLeft] < RightSubArray[idxRight]) {Array[i] = LeftSubArray[idxLeft];idxLeft++;} else {Array[i] = RightSubArray[idxRight];idxRight++;}}
}
void MergeSort(vector<int> &Array, int front, int end) {if (front >= end)return;int mid = (front + end) / 2;MergeSort(Array, front, mid);MergeSort(Array, mid + 1, end);Merge(Array, front, mid, end);
}

参考MOOC浙大数据结构

//C
/* L = 左边起始位置, R = 右边起始位置, RightEnd = 右边终点位置*/
void Merge( ElementType A[], ElementType TmpA[], int L, int R, int RightEnd ){/* 将有序的A[L]~A[R-1]和A[R]~A[RightEnd]归并成一个有序序列 */int LeftEnd, NumElements, Tmp;int i;LeftEnd = R - 1; /* 左边终点位置 */Tmp = L;         /* 有序序列的起始位置 */NumElements = RightEnd - L + 1;while( L <= LeftEnd && R <= RightEnd ) {if ( A[L] <= A[R] )TmpA[Tmp++] = A[L++]; /* 将左边元素复制到TmpA */elseTmpA[Tmp++] = A[R++]; /* 将右边元素复制到TmpA */}while( L <= LeftEnd )TmpA[Tmp++] = A[L++]; /* 直接复制左边剩下的 */while( R <= RightEnd )TmpA[Tmp++] = A[R++]; /* 直接复制右边剩下的 */for( i = 0; i < NumElements; i++, RightEnd -- )A[RightEnd] = TmpA[RightEnd]; /* 将有序的TmpA[]复制回A[] */
}
void Msort( ElementType A[], ElementType TmpA[], int L, int RightEnd ){/* 核心递归排序函数 */ int Center;if ( L < RightEnd ) {Center = (L+RightEnd) / 2;Msort( A, TmpA, L, Center );              /* 递归解决左边 */ Msort( A, TmpA, Center+1, RightEnd );     /* 递归解决右边 */  Merge( A, TmpA, L, Center+1, RightEnd );  /* 合并两段有序序列 */ }
}
void MergeSort( ElementType A[], int N ){/* 归并排序 */ElementType *TmpA;TmpA = (ElementType *)malloc(N*sizeof(ElementType));if ( TmpA != NULL ) {Msort( A, TmpA, 0, N-1 );free( TmpA );}else printf( "空间不足" );
}

6、快速排序

描述:

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

动图演示:

快速排序是目前感觉最厉害的。

代码:

#python
def quickSort(arr, left=None, right=None):left = 0 if not isinstance(left,(int, float)) else leftright = len(arr)-1 if not isinstance(right,(int, float)) else rightif left < right:partitionIndex = partition(arr, left, right)quickSort(arr, left, partitionIndex-1)quickSort(arr, partitionIndex+1, right)return arrdef partition(arr, left, right):pivot = leftindex = pivot+1i = indexwhile  i <= right:if arr[i] < arr[pivot]:swap(arr, i, index)index+=1i+=1swap(arr,pivot,index-1)return index-1def swap(arr, i, j):arr[i], arr[j] = arr[j], arr[i]
//C
void swap(int *x, int *y) {int t = *x;*x = *y;*y = t;
}void quick_sort_recursive(int arr[], int start, int end) {if (start >= end)return;int mid = arr[end];int left = start, right = end - 1;while (left < right) {while (arr[left] < mid && left < right)left++;while (arr[right] >= mid && left < right)right--;swap(&arr[left], &arr[right]);}if (arr[left] >= arr[end])swap(&arr[left], &arr[end]);elseleft++;if (left)quick_sort_recursive(arr, start, left - 1);quick_sort_recursive(arr, left + 1, end);
}void quick_sort(int arr[], int len) {quick_sort_recursive(arr, 0, len - 1);
}
//C++
template <typename T>
void quick_sort_recursive(T arr[], int start, int end) {if (start >= end)return;T mid = arr[end];int left = start, right = end - 1;//在整个范围内搜寻比枢纽元值小或大的元素,然后将左侧元素与右侧元素交换while (left < right) { //试图在左侧找到一个比枢纽元更大的元素while (arr[left] < mid && left < right)left++;//试图在右侧找到一个比枢纽元更小的元素while (arr[right] >= mid && left < right)right--;std::swap(arr[left], arr[right]); //交换元素}if (arr[left] >= arr[end])std::swap(arr[left], arr[end]);elseleft++;quick_sort_recursive(arr, start, left - 1);quick_sort_recursive(arr, left + 1, end);
}template <typename T>
void quick_sort(T arr[], int len) {quick_sort_recursive(arr, 0, len - 1);
}

参考MOOC浙大数据结构

//c
//判断数组规模,如果太小,直接就插入排序
void swap(int *a,int *b){int temp = *a;*a = *b;*b = temp;
}void InsertionSort( ElementType A[], int N ){int P, i;ElementType Tmp;for ( P=1; P<N; P++ ) {Tmp = A[P];for ( i=P; i>0 && A[i-1]>Tmp; i-- )A[i] = A[i-1];A[i] = Tmp;}
}ElementType Median3(ElementType A[], int Left, int Right){int Center=(Left+Right)/2;if(A[Left]>A[center])Swap(&A[Left], &A[center]);if(A[Left]>A[Right])Swap(&A[Left], &A[Right]);if(A[center]>A[Right])Swap(&A[Center], &A[Right]);/*此时A[Left]c=A[center]c=A[Right]*/Swap(&A[center], &A[Right-1]);  /*将基准Pivot藏到右边*//*只需要考虑A[Left+1]…A[Right-2]*/return A[Right-1];    /*返回基准 Pivot*/
}void Qsort(Elementrype A[], int Left, int Right){/*核心递归函数*/int pivot, Cutoff, Low, High;if(Cutoff<=Right-Left){    /*如果序列元素充分多,进入快排*/Pivot=Median3(A, Left, Right);    /*选基准*/Low=Left;High=Right-1;while(1){ /*将序列中比基准小的移到基准左边,大的移到右边*/while(A[++Low]<Pivot);while(A[--High]>pivot);if(Low<High) Swap(&A[Low], &A[High]);else break;}Swap(&A[Low], &A[Right-1]);   /*将基准换到正确的位置*/Qsort(A, Left, Low-1);    /*递归解决左边*/Qsort(A, Low+1, Right);  /*递归解决右边*/}else Insertionsort(A+Left, Right-Left+1);  /*元素太少,用简单排序*/
}void Quicksort(ElementType A[],int N){/*统一接口*/Qsort(A, 0, N-1);
}

7、堆排序

描述:

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

动图演示:

堆排序是其实就和之前的堆一样,但是我不太会。

代码:

#python
def buildMaxHeap(arr):import mathfor i in range(math.floor(len(arr)/2),-1,-1):heapify(arr,i)def heapify(arr, i):left = 2*i+1right = 2*i+2largest = iif left < arrLen and arr[left] > arr[largest]:largest = leftif right < arrLen and arr[right] > arr[largest]:largest = rightif largest != i:swap(arr, i, largest)heapify(arr, largest)def swap(arr, i, j):arr[i], arr[j] = arr[j], arr[i]def heapSort(arr):global arrLenarrLen = len(arr)buildMaxHeap(arr)for i in range(len(arr)-1,0,-1):swap(arr,0,i)arrLen -=1heapify(arr, 0)return arr
//C
void swap(int *a, int *b) {int temp = *b;*b = *a;*a = temp;
}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 { // 否則交換父子內容再繼續子節點和孫節點比較swap(&arr[dad], &arr[son]);dad = son;son = dad * 2 + 1;}}
}void heap_sort(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--) {swap(&arr[0], &arr[i]);max_heapify(arr, 0, i - 1);}
}
//C++
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 { // 否則交換父子內容再繼續子節點和孫節點比較swap(arr[dad], arr[son]);dad = son;son = dad * 2 + 1;}}
}void heap_sort(int arr[], int len) {// 初始化,i從最後一個父節點開始調整for (int i = len / 2 - 1; i >= 0; i--)max_heapify(arr, i, len - 1);// 先將第一個元素和已经排好的元素前一位做交換,再從新調整(刚调整的元素之前的元素),直到排序完畢for (int i = len - 1; i > 0; i--) {swap(arr[0], arr[i]);max_heapify(arr, 0, i - 1);}
}

参考MOOC浙大数据结构

void Swap( ElementType *a, ElementType *b )
{ElementType t = *a; *a = *b; *b = t;
}void PercDown( ElementType A[], int p, int N )
{ /* 改编代码4.24的PercDown( MaxHeap H, int p )    *//* 将N个元素的数组中以A[p]为根的子堆调整为最大堆 */int Parent, Child;ElementType X;X = A[p]; /* 取出根结点存放的值 */for( Parent=p; (Parent*2+1)<N; Parent=Child ) {Child = Parent * 2 + 1;if( (Child!=N-1) && (A[Child]<A[Child+1]) )Child++;  /* Child指向左右子结点的较大者 */if( X >= A[Child] ) break; /* 找到了合适位置 */else  /* 下滤X */A[Parent] = A[Child];}A[Parent] = X;
}void HeapSort( ElementType A[], int N )
{ /* 堆排序 */int i;for ( i=N/2-1; i>=0; i-- )/* 建立最大堆 */PercDown( A, i, N );for ( i=N-1; i>0; i-- ) {/* 删除最大堆顶 */Swap( &A[0], &A[i] ); /* 见代码7.1 */PercDown( A, 0, i );}
}

8、计数排序

描述:

计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。

动图演示:

如果不是一定需要比较的例子,计数要快不知道多少,比如工龄统计。

代码:

#python
def countingSort(arr, maxValue):bucketLen = maxValue+1bucket = [0]*bucketLensortedIndex =0arrLen = len(arr)for i in range(arrLen):if not bucket[arr[i]]:bucket[arr[i]]=0bucket[arr[i]]+=1for j in range(bucketLen):while bucket[j]>0:arr[sortedIndex] = jsortedIndex+=1bucket[j]-=1return arr
//C
void print_arr(int *arr, int n) {int i;printf("%d", arr[0]);for (i = 1; i < n; i++)printf(" %d", arr[i]);printf("\n");
}void counting_sort(int *ini_arr, int *sorted_arr, int n) {int *count_arr = (int *) malloc(sizeof(int) * 100);int i, j, k;for (k = 0; k < 100; k++)count_arr[k] = 0;for (i = 0; i < n; i++)count_arr[ini_arr[i]]++;for (k = 1; k < 100; k++)count_arr[k] += count_arr[k - 1];for (j = n; j > 0; j--)sorted_arr[--count_arr[ini_arr[j - 1]]] = ini_arr[j - 1];free(count_arr);
}

9、桶排序

描述:

桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。

动图演示:


看来计数排序是真的很好用,不然不会有plus!

代码:

struct ListNode{explicit ListNode(int i=0):mData(i),mNext(NULL){}ListNode* mNext;int mData;
};ListNode* insert(ListNode* head,int val){ListNode dummyNode;ListNode *newNode = new ListNode(val);ListNode *pre,*curr;dummyNode.mNext = head;pre = &dummyNode;curr = head;while(NULL!=curr && curr->mData<=val){pre = curr;curr = curr->mNext;}newNode->mNext = curr;pre->mNext = newNode;return dummyNode.mNext;
}ListNode* Merge(ListNode *head1,ListNode *head2){ListNode dummyNode;ListNode *dummy = &dummyNode;while(NULL!=head1 && NULL!=head2){if(head1->mData <= head2->mData){dummy->mNext = head1;head1 = head1->mNext;}else{dummy->mNext = head2;head2 = head2->mNext;}dummy = dummy->mNext;}if(NULL!=head1) dummy->mNext = head1;if(NULL!=head2) dummy->mNext = head2;return dummyNode.mNext;
}void BucketSort(int n,int arr[]){vector<ListNode*> buckets(BUCKET_NUM,(ListNode*)(0));for(int i=0;i<n;++i){int index = arr[i]/BUCKET_NUM;ListNode *head = buckets.at(index);buckets.at(index) = insert(head,arr[i]);}ListNode *head = buckets.at(0);for(int i=1;i<BUCKET_NUM;++i){head = Merge(head,buckets.at(i));}for(int i=0;i<n;++i){arr[i] = head->mData;head = head->mNext;}
}

10、基数排序

描述:

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

动图演示:

基数排序就像扑克分类!

是数字还是色号?

代码:

//C
void print(int *a, int n) {int i;for (i = 0; i < n; i++) {printf("%d\t", a[i]);}
}void radixsort(int *a, int n) {int i, b[MAX], m = a[0], exp = 1;for (i = 1; i < n; i++) {if (a[i] > m) {m = a[i];}}while (m / exp > 0) {int bucket[BASE] = { 0 };for (i = 0; i < n; i++) {bucket[(a[i] / exp) % BASE]++;}for (i = 1; i < BASE; i++) {bucket[i] += bucket[i - 1];}for (i = n - 1; i >= 0; i--) {b[--bucket[(a[i] / exp) % BASE]] = a[i];}for (i = 0; i < n; i++) {a[i] = b[i];}exp *= BASE;#ifdef SHOWPASSprintf("\nPASS   : ");print(a, n);
#endif}
}
//C++
//辅助函数,求数据的最大位数
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 overflowmaxData /= 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;//进行d次排序for(i = 1; i <= d; i++) {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;
}

参考MOOC浙大数据结构

//c
/* 基数排序 - 次位优先 *//* 假设元素最多有MaxDigit个关键字,基数全是同样的Radix */
#define MaxDigit 4
#define Radix 10/* 桶元素结点 */
typedef struct Node *PtrToNode;
struct Node {int key;PtrToNode next;
};/* 桶头结点 */
struct HeadNode {PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];int GetDigit ( int X, int D )
{ /* 默认次位D=1, 主位D<=MaxDigit */int d, i;for (i=1; i<=D; i++) {d = X % Radix;X /= Radix;}return d;
}void LSDRadixSort( ElementType A[], int N )
{ /* 基数排序 - 次位优先 */int D, Di, i;Bucket B;PtrToNode tmp, p, List = NULL; for (i=0; i<Radix; i++) /* 初始化每个桶为空链表 */B[i].head = B[i].tail = NULL;for (i=0; i<N; i++) { /* 将原始序列逆序存入初始链表List */tmp = (PtrToNode)malloc(sizeof(struct Node));tmp->key = A[i];tmp->next = List;List = tmp;}/* 下面开始排序 */ for (D=1; D<=MaxDigit; D++) { /* 对数据的每一位循环处理 *//* 下面是分配的过程 */p = List;while (p) {Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 *//* 从List中摘除 */tmp = p; p = p->next;/* 插入B[Di]号桶尾 */tmp->next = NULL;if (B[Di].head == NULL)B[Di].head = B[Di].tail = tmp;else {B[Di].tail->next = tmp;B[Di].tail = tmp;}}/* 下面是收集的过程 */List = NULL; for (Di=Radix-1; Di>=0; Di--) { /* 将每个桶的元素顺序收集入List */if (B[Di].head) { /* 如果桶不为空 *//* 整桶插入List表头 */B[Di].tail->next = List;List = B[Di].head;B[Di].head = B[Di].tail = NULL; /* 清空桶 */}}}/* 将List倒入A[]并释放空间 */for (i=0; i<N; i++) {tmp = List;List = List->next;A[i] = tmp->key;free(tmp);}
}/* 基数排序 - 主位优先 *//* 假设元素最多有MaxDigit个关键字,基数全是同样的Radix */#define MaxDigit 4
#define Radix 10/* 桶元素结点 */
typedef struct Node *PtrToNode;
struct Node{int key;PtrToNode next;
};/* 桶头结点 */
struct HeadNode {PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];int GetDigit ( int X, int D )
{ /* 默认次位D=1, 主位D<=MaxDigit */int d, i;for (i=1; i<=D; i++) {d = X%Radix;X /= Radix;}return d;
}void MSD( ElementType A[], int L, int R, int D )
{ /* 核心递归函数: 对A[L]...A[R]的第D位数进行排序 */int Di, i, j;Bucket B;PtrToNode tmp, p, List = NULL; if (D==0) return; /* 递归终止条件 */for (i=0; i<Radix; i++) /* 初始化每个桶为空链表 */B[i].head = B[i].tail = NULL;for (i=L; i<=R; i++) { /* 将原始序列逆序存入初始链表List */tmp = (PtrToNode)malloc(sizeof(struct Node));tmp->key = A[i];tmp->next = List;List = tmp;}/* 下面是分配的过程 */p = List;while (p) {Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 *//* 从List中摘除 */tmp = p; p = p->next;/* 插入B[Di]号桶 */if (B[Di].head == NULL) B[Di].tail = tmp;tmp->next = B[Di].head;B[Di].head = tmp;}/* 下面是收集的过程 */i = j = L; /* i, j记录当前要处理的A[]的左右端下标 */for (Di=0; Di<Radix; Di++) { /* 对于每个桶 */if (B[Di].head) { /* 将非空的桶整桶倒入A[], 递归排序 */p = B[Di].head;while (p) {tmp = p;p = p->next;A[j++] = tmp->key;free(tmp);}/* 递归对该桶数据排序, 位数减1 */MSD(A, i, j-1, D-1);i = j; /* 为下一个桶对应的A[]左端 */} }
}void MSDRadixSort( ElementType A[], int N )
{ /* 统一接口 */MSD(A, 0, N-1, MaxDigit);
}


我还是喜欢浙大的代码风格!

参考

  • 百度百科
  • https://www.runoob.com/
  • https://github.com/hustcc/JS-Sorting-Algorithm

一文总结十大经典排序算法(思维导图 + 动图演示 + 代码实现 C/C++/Python + 致命吐槽)相关推荐

  1. 一文搞掂十大经典排序算法

    一文搞掂十大经典排序算法 今天整理一下十大经典排序算法. 1.冒泡排序 --越小的元素会经由交换慢慢"浮"到数列的顶端 算法演示 算法步骤 比较相邻的元素.如果第一个比第二个大,就 ...

  2. C++实现桶排序——十大经典排序算法之九【GIF动画+完整代码+详细注释】

    十大经典排序算法系列博客-->传送门 桶排序是计数排序的升级版.它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定.桶排序 (Bucket sort)的工作的原理:假设输入数据服从均 ...

  3. 十大经典排序算法及比较与分析 ( 动画演示 ) ( 可视化工具 )

    可视化工具及动画展示:旧金山大学 (usfca)|数据结构可视化工具 排序算法概念及描述:1.0 十大经典排序算法(文章部分内容引用自改文章) 参考:邓俊辉 的数据结构 本文未对排序算法概念进行详细说 ...

  4. 十大经典排序算法最强总结(含JAVA代码实现),大厂 HR 如何面试

    写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家.扫码加微信好友进[程序员面试学习交流群],免费领取.也欢迎各位一起在群里探讨技术. 最近 ...

  5. 十大经典排序算法最强总结(含JAVA代码实现)

    最近几天在研究排序算法,看了很多博客,发现网上有的文章中对排序算法解释的并不是很透彻,而且有很多代码都是错误的,例如有的文章中在"桶排序"算法中对每个桶进行排序直接使用了Colle ...

  6. 十大经典排序算法最强总结(含Java代码实现),从零开始学springboot百度网盘

    比较相邻的元素.如果第一个比第二个大,就交换它们两个: 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数: 针对所有的元素重复以上的步骤,除了最后一个: 重 ...

  7. 一文搞定十大经典排序算法

    更多内容关注公众号:SAP Technical 一.排序算法概述 1.定义 将杂乱无章的数据元素,通过一定的方法按关键字顺序排列的过程叫做排序. 2.分类 十种常见排序算法可以分为两大类: 非线性时间 ...

  8. 11月14日云栖精选夜读 | 动画+原理+代码,解读十大经典排序算法

    排序算法是<数据结构与算法>中最基本的算法之一. 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过 ...

  9. 按复杂度有效性递减排序_十大经典排序算法:python源码实现,通俗深入讲解

    概述 提示:本文上万字,陆陆续续疏理知识点加测试代码,耗时近一个月.阅读时长40分钟左右. 本文将十大经典排序算法进行汇总,从源码实现.复杂度.稳定性进行分析,并对每种排序的特性进行点评.对典型算法, ...

最新文章

  1. 大规模集群中Docker镜像如何分发管理?试试Uber刚开源的Kraken
  2. BZOJ5323 洛谷4562:[JXOI2018]游戏——题解
  3. 一级域名和二级域名的区别是什么?作用怎样?
  4. python 3.7.3 运算7错误_Python中通常不应该犯的7个错误
  5. python编程工资-2019年Python就业薪资怎么样?看完你就了解了
  6. Windows系统MySQL安装配置
  7. research paper for management science
  8. DCMTK:OFStandard类的测试程序
  9. Windows - node版本管理工具NVM
  10. lcp mysql cluster_Mysql Cluster 非root用户启动ndbd节点报错
  11. c+++11并发编程语言,C++11并发编程:多线程std:thread
  12. java泛型实验报告,java实验报告异常集合类和泛型
  13. CCF NOI1013 识别三角形
  14. 检查数组中的子字符串– Java,Python和Swift
  15. vue多html标签,Vue实现多标签选择器
  16. 深度强化学习DQN(Deep Q Network)原理及例子:如何解决迷宫问题,附源码
  17. 2d unity 多物体 射线_Unity3D 之射线检测
  18. SRE稳定性指标:MTBF、MTTR
  19. 6.后台验证码-session作用域
  20. 苹果app退款_??充值消费退款

热门文章

  1. 电脑上不去网的6点原因
  2. pythonocc的BRepPrimAPI在OCC.Core.BRepPrimAPI里
  3. 嵌入式软件工程师 秋招笔试题
  4. 什么是量子霸权?我们如何才能实现它?
  5. 专业的个人记帐软件 爱上记帐 1.0.1
  6. 高清智能安防系统旅游景区解决方案分析
  7. 顺丰速运——深圳二面(19分钟)
  8. 图象关于y轴对称是什么意思_函数图象关于y轴对称是什么函数
  9. 在线播放ppt html5,强大的HTML5幻灯片系统:H5Slides
  10. 北斗组网大功告成!你的手机真的能连上北斗吗