--- title: "排序合集" date: 2022-05-19T10:34:31+08:00 --- 内容参考:[十大经典排序算法](https://sort.hust.cc/) --------------------- #### 归并排序 基本思想: 将待排序元素分为大小大致相同的两个子集合,分别对两个子集合进行排序,最终将排好序的子集合并成为所要求的排好序的集合 JAVA实现 ``` java public static void mergeSort(Comparable[]a) { Comparable []b=new Comparable[a.length]; int s=1; while(sm) for(int q=j;q<=r;q++) { d[k++]=c[q]; } else { for(int q=i;q<=m;q++) d[k++]=c[q]; } } ``` C++实现 ```c++ void merge(vector& arr,int l,int mid,int r) { int index = 0 ; int ptrL = l; int ptrR = mid; static vectortempary; if(arr.size() > tempary.size()) { tempary.resize(arr.size());//更新缓存数组长度 } while(ptrL ! = mid && ptrR ! = r) { if(arr[ptrL] < arr[ptrR])//比较左右分组后数组长度 { tempary[index++] = arr[ptrL++]; } else { tempary[index++] = arr[ptrR++]; } } while(ptrL ! = mid) { tempary[index++] = arr[ptrL++]; } while(ptrR ! = r) { tempary[index++] = arr[ptrR++]; } copy(tempary.begin(),tempary.begin()+index,arr.begin()+l) } void mergeSort(vector& arr,int l,int r) { if(r - l <= 1>) { return; } int mid = ( l + r ) / 2; mergeSort(arr,l,mid); mergeSort(arr,mid,r);//递归排序 merge(arr,l,mid,r);//合并数组 } ``` ----------------------- #### 快速排序 基本思想 对于输入的数组a[p:r] 1. 分解:以a[p]为基准元素将a[p:r]分为3段a[p:q-1],a[q]和a[q+1:r]
使得a[p:q-1]中任何元素小于等于a[q]
a[q+1:r]中任何元素大于等于a[q] 2. 递归求解:通过递归调用排序算法,分别对q[p:q-1]和a[q+1:r]进行排序 3. 合并:由于对a[p:q-1]和a[q+1:r]的排序是就地进行,所以在a[p:q-1]和a[q+1:r]完成排序后无需额外计算,a[p:r]的排序就已经完成 JAVA实现 ```java public class qSort { private static void qSort(int p,int r) { if(px的元素交换到右边区域 while(true) { while(a[++i].compareTo(x)<0&&i0); if(i>=j) break; MyMath.swap(a,i,j); } a[p]=a[j]; a[j]=x; return j; } } ``` C++实现 ```c++ Paritition1(int A[],int low,int high) { int pivot = A[low]; while (low < high) { while(low < high && A[high] >= pivot) { --high; } A[low] = A[high]; } while (low < high && A[low] <= pivot) { ++low; } A[low] = pivot; return low; } void QuickSort(int A[],int low,int high) { if(low arr[j+1]) { int tmp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tmp; flag = false; } } if(flag) { break; } return arr; } } ``` C++ ```c++ void BubbleSort(int arr[],int n) { for(int i = 0 ; i < n - 1;i++) { for(int j = 0;j < n-i-1;j++)//比较大小 { if(arr[j]>arr[j+1]) } int temp = arr[j];//交换位置 arr[j] = arr[j+1]; arr[j+1]=temp; } } ``` ------------- #### 选择排序 主要思想 1. 在没排序的序列中找到最小的元素,存放到开始位置 2. 在剩余元素中找到最小元素,存放到前一个元素的下一个位置 3. 重复步骤直到完成 JAVA ```java public class SelectionSort { public int[] sort(int[] sourceArray) { //复制到目标数组 int[] arr = Arrays.copyof(sourceArray,sourceArray.length); //计算比较次数 for(int i = 0;i < arr.length - 1;i++) { int min = i; for (int j = i + 1;j < arr.length;j++) { if(arr[j] < arr[min]) { //记录当前找到的最小元素的下标 min = j; } } //将找到的最小值和i位置所在的值进行交换 if(i ! = min) { int tmp = arr[i]; arr[i] = arr[min]; arr[min] = tmp; } } return arr; } } ``` C++ ```c++ void selectSort(vector& nums,int n) { for(int i = 0; i < n;i++) { int min = i; for(int j = i+1;i < n;j++)//遍历取得最小值 { if(nums[j] < nums[min]) { min = j; } } if(min != i) //移动到末尾 { int tmp = nums[i]; nums[i] = nums[min]; nums[min] = tmp; } } } ``` -------------------------------------- #### 插入排序 1. 将第一个元素视为已排列的有序数组,之后的元素视为未排列的无序数组 2. 从头到尾依次遍历未排序序列,将遍历到的元素插入到有序数组的适当位置 JAVA ```java public class InsertionSort { public int[] sort(int[] sourceArray) { //复制到目标数组 int[] arr = Arrays.copyof(sourceArray,sourceArray.length); //从下标为1的元素开始遍历,寻找合适位置插入 for(int i = 1; i < arr.length;i++) { //缓存要插入的值 int tmp = arr[i]; //依次与有序数列中的数比较,找到合适位置 int j = i; while(j>0 && tmp=0 && A[j]>get)//与已排序的有序数组比较 { A[j+1]=A[j];//如果该数更大则右移 j--; } A[j+1] = get; } } ``` ------------------------------------------ #### 希尔排序 1. 将整个待排列数组分为增量序列$t_1,t_2,\cdots,t_k且t_i>t_j,t_k=1$ 2. 按照增量序列的个数K,对序列进行k趟排序 3. 每次排序时根据$t_i$的值将未排序序列分割为若干个长度为m的子序列,分别进行插入排序。当i为1时,整个序列视为一个表 JAVA ```java public class ShellSort { public int[] sort(int[] sourceArray) { //复制到目标数组 int[] arr = Arrays.copyof(sourceArray,sourceArray.length); int gap =1; while(gap < arr.length/3) { gap = gap * 3 + 1; } while(gap > 0) { for(int i =gap; i= 0 && arr[j]>tmp) { arr[j+gap]=arr[j]; j-=gap; } arr[j+gap] = tmp; } gap = (int) Math.floor(gap/3); } return arr; } } ``` C++ ```c++ const int INCRGAP = 3; void shellSort(int a[],int len) { int insertNum = 0; unsigned gap = len/INCRGAP + 1;//初始化步长,应该确保步长为1 while(gap) { for(unsigned i = gap;i=gap && insertNum< a[j-gap])//寻找插入位置 { a[j] = a[j-gap]; j -= gap; } a[j] = insertNum; } gap = gap/INCRGAP; } } ``` ----------------------------------- #### 堆排序 1. 将要排序的数组构造为堆,根据升序或降序选择大顶堆或小顶堆 2. 互换堆首和堆尾 3. 将堆的尺寸缩小1,将新的数组顶点位置调整到对应位置 4. 重复步骤2,直到堆的尺寸为1 JAVA ```java public class HeapSort { public int[] sort(int[] sourceArray) { int[] arr = Arrays.copyof(sourceArray,sourceArray.length); int len = arr.length; buildMaxHeap(arr,len); for(int i = len - i; i > 0;i--) { swap(arr,0,i); len--; heapify(arr,0,len); } return arr; } private void buildMaxHeap(int[],int len) { for(int i =(int) Math.floor(len/2);i>= 0;i--) { heapify(arr,i,len); } } private void heapify(int[] arr,int i,int len) { int left =2 * i + 1; int right = 2 * i + 2; int largest = i; if(left < len && arr[left]>arr[largest]) { largest = left; } if(right < len && arr[right]> arr[largest]) { largest = right; } if(largest !=i) { swap(arr,i,largest); heapify(arr,largest,len); } } private void swap(int[] arr,int i,int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } ``` C++ ```c++ void buildMaxHeap(int A[],int n) { for(int i =n/2-1;i >= 0;i--) { maxHeapIfy(A,i,n); } } void maxHeapIfy(int A[],int i,int n) { int l = 2 * i + 1; int r = 2 * i + 1; int largest = i; if(lA[largest]) { largest = l ; } if(lA[largest]) { largest = r ; } if(largest != i) { swap(A[i],A[largest]); maxHeapIfy(A,largest,n); } } void heapSort(int A[],int n) { buildMaxHeap(A,n); for(int i = n-1;i> 0 ;i--) { swap(A[0],A[i]); maxHeapIfy(A,0,i); } } ``` ------------------------------------- #### 计数排序 1. 找出待排序的数组中国最大和最小的元素,从而确定缓存数组的最大长度 2. 根据每个值为i的元素出现的次数,存入缓存数组的第i项 3. 累加所有计数 4. 反向填充目标数组 JAVA ```java public class HeapSort { public int[] sort(int[] sourceArray) { int[] arr = Arrays.copyof(sourceArray,sourceArray.length); int maxValue = getMaxValue(arr); return countingSort(arr,maxValue); } private int[] countingSort(int[] arr,int maxValue) { int bucketLen = maxValue + 1; int[] bucket = new int[bucketLen]; for(int value :arr) { bucket[value]++; } int sortedIndex = 0; for(int j = 0; j < bucketLen;j++) { while(bucket[j]>0) { arr[sortedIndex++] = j; bucket[j]--; } } return arr; } private int getMaxValue(int[] arr) { int maxValue = arr[0]; for(int value : arr) { if(maxValue < value) { maxValue = value; } } return maxValue; } } ``` C++ ```c++ #include #include #include #include #include using namespace std; vector CountSort(const vector& vec) { int length = vec.size(); if(length <= 1) { return vec; } else { int max = *max_element(vec.begin(),vec.end()); int min = *min_element(vec.begin(),vec.end()); vector countArray(max - min + 1,0); for(int i = 0;i < length;i++) { ++countArray[vec[i] - min]; } vector sortArray; for(int i = 0;i < countArray.size();++i) { for(int j = 0;j < countArray[i];++j) { sortArray.push_back(min + i); } } return sortArray; } } ``` ----------------------------- #### 桶排序 1. 利用函数映射关系将待排序数组的元素分配到桶中 2. 将元素在桶中排序 ```java public class BuckSort { private static final InserSort insertSort = new InsertSort(); public int[] sort(int[] sourceArray) throws Exception { int[] arr = Arrays.copy0f(sourceArray,sourceArray.length); return bucketSort(Arr,5); } private int[] bucketSort(int[] arr,int bucketSize) throws Exception { if(arr.length == 0) { return arr; } int minValue = arr[0]; int maxValue = arr[0]; for(int value : arr) { if(value < minValue) { minValue = value; } else if(value > maxValue) { maxValue = value; } } int bucketCount = (int) Math.floor((maxValue - minValue)/bucketSize) + 1; int[][] buckets = new int[bucketCount][0]; for(int i = 0;i < arr.length;i++) { int index = (int)Math.floor((arr[i]-minValue)/bucketSize); buckets[index] = arrAppend(buckets[index],arr[i]); } int arrIndex = 0; for(int[] bucket : buckets) { if(buckets.length <= 0) { continue; } bucket = insertSort.sort(bucket); for(int value : bucket) { arr[arrIndex++] = value; } } return arr; } /*自动扩容桶的数量*/ private int[] arrAppend(int[] arr,int value) { arr = Arrays.copy0f(arr,arr.length+1); arr[arr.length - 1] = value; return arr; } } ``` C++ ```c++ #include #include #include using namespace std; const int BUCKET_NUM = 10; 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 BuckSort(int n,int arr[]) { vector buckets(BUCKET_NUM,(ListNode*)(0)); for(int i=0;imData; head = head->mNext; } } ``` ----------------------------- #### 基数排序 将整数按位数分割为不同数字,按各位数比较大小 在桶的分配方式上根据键值的每位数字来分配桶 ```java public class RadixSort { public int[] sort(int[] sourceArray) throws Exception { int[] arr = Arrays.copy0f(sourceArray,sourceArray.length); int maxDigit = getMaxDigit(arr); return radixSort(arr,maxDigit); } /* 获取最高位数 */ private int getMaxDigit(int[] arr) { int maxValue = getMaxValue(arr); return getNumLenght(maxValue); } private int getMaxValue(int[] arr) { int maxValue = arr[0]; for(int value : arr) { if(maxValue < value) { maxValue = value; } } return maxValue; } private int getNumLenght(long num) { if(num == 0) { return 1; } int length = 0; for(long temp = num;temp !=0;temp/=10) { lenght++; } return lenght; } private int[] radixSort(int[] arr,int maxDigit) { int mod =10; int dev =1; for(int i = 0;i < maxDigit;i++,dev*=10,mod *= 10) { int[][] counter = new int[mod * 2][0]; for(int j= 0;j= p ) { maxData /= 10; ++d; } return d; } void radixSort(int data[],int n) { int d = maxbit(data,n); int *tmp = new int[n]; int *count = new int[n]; int i,j,k; int radix = 1; 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]; } for(j = n-1;j>= 0 ;j--) { k = (data[j]/radix) % 10; tmp[count[k] - 1] = data[j]; count[k]--; } for(j = 0;j < n;j++) { data[j] = tmp[j]; } radix = radix * 10; } delete []tmp; delete []count; } ``` -----------------------------