InkSoul/content/algorithm/排序合集.md

1067 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
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(s<a.length)
{
mergePass(a,b,s);//合并到数组a
s+=s;
mergePass(b,a,s);//合并到数组b
s+=s;
}
}
public static void mergePass(Comparable []x,Comparable[]y,int s)
{
int i =0;
while(i<=x.length-2*s)
{
//合并大小为s的相邻两段子数组
merge(x,y,i,i+s-1,i+2*s-1);
i=i+2*s;
}
//剩下的元素个数小于2s
if(i+s<x.length)
merge(x,y,i,i+s-1,x.length-1);
else
//剩余元素复制到y
for(int j=i;j<x.length;j++)
y[j]=x[j];
}
public static void merge(Comparable[]c,Comparable[]d,int l,int m,int r)
{
//合并c[l:m]和c[m+1:r]到d[l:r]
int i=l,j=m+l,k=l;
while((i<=m)&&(j<=r))
if(c[i].compareTo(c[j])<=0)
{
d[k++]=c[i++];
}
else
{
d[k++]=c[j++];
}
if(i>m)
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<int>& arr,int l,int mid,int r)
{
int index = 0 ;
int ptrL = l;
int ptrR = mid;
static vector<int>tempary;
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<int>& 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]
<br>使得a[p:q-1]中任何元素小于等于a[q]
<br>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(p<r)
{
int q = partition(p,r);
qSort(p,q-1);
qSort(q+1,r);
}
}
private static int partition(int p,int r)
{
int i = p,
j=r+1;
Comparable x = a[p];
//将<x的元素交换到左边区域
//将>x的元素交换到右边区域
while(true)
{
while(a[++i].compareTo(x)<0&&i<r);
while(a[--j].compareTo(x)>0);
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<high)
{
int pivot = Paritition1(A,low,high);
QuickSort(A,low,pivot - 1);
QuickSort(A,pivot + 1high);
}
}
```
-------------------
#### 冒泡排序
主要思想:
1. 对一对相邻的元素比较,前者大于后者则交换它们
2. 对数组中所有元素都做此操作,直到最后,最大的数会向泡泡一样冒到数组末尾
3. 重复操作,每次都跳过上一次的最后一个元素,直到没有元素需要比较
JAVA
```java
public class BubbleSort
{
public int[] sort(int[] sourceArray)
{
//复制到目标数组
int[] arr = Arrays.copyof(sourceArray,sourceArray.length);
}
for(int i = 1; i < arr.length; i++)
{
boolean flag =true;
for(int j = 0;j < arr.length - i;j++)
{
if(arr[j] > 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<int>& 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<arr[j-1])
{
arr[j] = arr[j-1];
j--;
}
//插入
if(j != i)
{
arr[j] = tmp
}
}
return arr;
}
}
```
C++
```c++
void InsertionSort(int A[],int n)
{
for(int i=1;i<n;i++)
{
int get = A[i]; //缓存要排序的数
int j = i - 1;
while (j>=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<arr.length;i++)
{
int tmp = arr[i];
int j = i-gap;
while(j >= 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<len;++i)//分组子序列
{
insertNum = a[i];//缓存当前元素值
unsigned j = i;
while(j>=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(l<n && A[l]>A[largest])
{
largest = l ;
}
if(l<n && A[r]>A[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 <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
using namespace std;
vector<int> CountSort(const vector<int>& 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<int> countArray(max - min + 1,0);
for(int i = 0;i < length;i++)
{
++countArray[vec[i] - min];
}
vector<int> 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 <iterator>
#include <iostream>
#include <vector>
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<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;
}
}
```
-----------------------------
#### 基数排序
将整数按位数分割为不同数字,按各位数比较大小
在桶的分配方式上根据键值的每位数字来分配桶
```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<arr.length;j++)
{
int bucket = ((arr[j]%mod)/dev)+mod;
counter[bucket] = arrAppend(counter[bucket],arr[j]);
}
int pos = 0;
for(int[] bucke:counter)
{
for(int value :bucket)
{
arr[pos++] = value;
}
}
}
return arr;
}
//自动扩容
private int[] arrAppend(int[] arr,int value)
{
arr = Arrays.copy0f(arr.length + 1);
arr[arr.length - 1] = value;
return arr;
}
}
```
C++
```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 (maxDate >= 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;
}
```
-----------------------------