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

1067 lines
20 KiB
Markdown
Raw Permalink Normal View History

2023-06-18 23:16:41 +08:00
---
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;
}
```
-----------------------------