基本的排序算法
1. 最常见简单的冒泡排序:
基本思想:
对当前还未排序好的所有数值,依次对相邻的两个数进行比较和调整。比较发现他们的排序和排序要求相反时,就将他们互换位置。
算法如下:
public void bubbleSort(@NotNull int[] a) {
//r:顺序两两比较,最终进行数组长度-1次
int r = a.length - 1;
for (int i = 0; i < r; i++) {
for (int j = 0; j < r - i; j++) {
//正序排序, 当前数比后一个数大,交换位置
if (a[j] > a[j + 1]) {
exchangeArray(a, j, j + 1);
}
}
}
}
public void exchangeArray(int[] a, int j, int k) {
int temp = a[j];
a[j] = a[k];
a[k] = temp;
}
2. 快速排序
基本思想:
选择一个元素,将待排序的元素和这个基元素比大小分成两部分,再以同样方法处理这两个部分。
算法如下:
/**
* 快速排序(二分法),小的放左边 大的放右边
*
* @param a 需要排序的数据
* @param l 左边界索引
* @param r 右边界索引
*/
public void quickSort(@NotNull int[] a, int l, int r) {
int middle = a[(l + r) / 2], lp = l, rp = r, temp;
do {
//从左边遍历到大于middle的数的索引
while (a[lp] < middle && lp < r) {
lp++;
}
//从右边遍历到小于middle的数的索引
while (a[rp] > middle && rp > l) {
rp--;
}
if (lp <= rp) {
//大的放到右边 小的放到左边
exchangeArray(a, lp, rp);
}
} while (lp <= rp);
//右边重复动作
if (lp < r) {
quickSort(a, lp, r);
}
//左边重复动作
if (rp > l) {
quickSort(a, l, rp);
}
}
public void exchangeArray(int[] a, int j, int k) {
int temp = a[j];
a[j] = a[k];
a[k] = temp;
}
3. 直接插入排序
基本思想:将未排序的数值直接插入有序的一组数中,使得插入后的这组数还是有序的。
算法如下:
/**
* 插入排序:将未排序的数值直接插入有序的一组数中,使得插入后的这组数还是有序的
*
* @param a 待排序数组
*/
public void insertSort(int[] a) {
int temp;
int i = 0;
while (i < a.length) {
int j = i - 1;
temp = a[i];
//将大于temp的值整体后移一个位置,并获取到temp在当前有序数组的索引位置
while (j >= 0 && a[j] > temp) {
a[j + 1] = a[j];
j--;
}
//将 temp值放入当前有序数组的索引位置
a[j + 1] = temp;
i++;
}
}
4. 希尔排序(最小增量排序)
基本思想:
先将要排序的一组数按增量d(n/2,n为数组长度)分成若干组,每组中记录的下标相差d,对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2取奇数)对它进行分组,再在每组中进行插入排序,当增量减小到1时,进行插入排序,就完成了。
算法如下:
/**
* 希尔排序(最小增量排序):先将要排序的一组数按增量d(n/2,n为数组长度)分成若干组,<br/>
* 每组中记录的下标相差d,对每组中全部元素进行直接插入排序,<br/>
* 然后再用一个较小的增量(d/2取奇数)对它进行分组,<br/>
* 再在每组中进行插入排序,当增量减小到1时,进行插入排序,就完成了
*
* @param a
*/
public void shellSort(int[] a) {
double d1 = a.length;
while (true) {
//d:分组增量 x:分组内索引
int d = a.length / 2, x = 0;
while (x < d) {
//分组内索引增量
int i = x + d;
while (i < a.length) {
//以分组为单位进行插入排序
int j = i - d;
int temp = a[i];
while (j >= 0 && a[j] > temp) {
a[j + d] = a[j];
j += d;
}
a[j + d] = temp;
i += d;
}
x++;
}
if (d == 1) {
break;
}
}
}
5. 简单选择排序
基本思想:
在要排序的一组数中,选出最小的数和第一个数交互位置,剩下的中再挑最小的放第二位,以此类推。
算法如下:
public void selectSort(int[] a){
int position=0;
for (int i = 0; i < a.length; i++) {
int j=i+1;
position=i;
int temp=a[i];
for (; j <a.length ; j++) {
if (a[j]<temp){
temp=a[j];
position=j;
}
}
a[position]=a[i];
a[i]=temp;
}
}
6. 堆排序
基本思想:
树形选择排序,对简单选择排序的有效改进。
根的数最大,将根和一个叶交换,踢出最大数,再重新建堆依次类推。
算法如下:
public void heapSort(int[] a){
for (int i = 0; i < a.length-1; i++) {
//建大顶堆
buildMaxHeap(a,a.length-1-i);
swap(a,0,a.length-1-i);
}
}
private void buildMaxHeap(int[] data,int lastIndex){
//从最后一个节点的父节点开始
for (int i = (lastIndex-1)/2; i >=0; i--) {
//k保存正在判断的节点
int k=i;
//如果当前k节点的子节点存在
while (k*2+1<=lastIndex){
//k节点的左子节点的索引
int biggerIndex=2*k+1;
//如果biggerIndex<lastIndex,
//即biggerIndex+1代表的k节点的右子节点存在
if (biggerIndex<lastIndex){
//若右子节点的值较大
if (data[biggerIndex]<data[biggerIndex+1]){
//总是记录较大子节点的索引
biggerIndex++;
}
}
//如果k节点的值小于其较大子节点的值
if (data[k]<data[biggerIndex]){
//交换它们
swap(data,k,biggerIndex);
//将biggerIndex 赋予给k,开始while循环的下一个循环
//重新包装k节点的值大于其左右节点的值
k=biggerIndex;
}else {
break;
}
}
}
}
private void swap(int[] data, int i, int j) {
int tmp=data[i];
data[i]=data[j];
data[j]=tmp;
}
7. 归并排序
基本思想:
将两个或以上有序表合并成一个新的有序表。
即把待排序的数组分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
算法如下:
public void mergeSort(int[] a, int left, int right) {
if (left < right) {
//找出中间索引
int center = (left + right) / 2;
//对左边数组进行递归
mergeSort(a, left, center);
//对右边数组进行递归
mergeSort(a, center + 1, right);
//合并
merge(a, left, center, right);
}
}
private void merge(int[] a, int left, int center, int right) {
int[] tmpArr = new int[a.length];
int mid = center + 1;
//third记录中间数组索引
int third = left;
int tmp = left;
//从两个数组中取出最小的放入中间数组
while (left <= center && mid <= right) {
if (a[left] <= a[mid]) {
tmpArr[third++] = a[left++];
} else {
tmpArr[third++] = a[mid++];
}
}
//剩余部分依次放入中间数组
while (mid <= right) {
tmpArr[third++] = a[mid++];
}
while (left <= center) {
tmpArr[third++] = a[left++];
}
//将中间数组中的内容复制回原数组
while (tmp <= right) {
a[tmp] = tmpArr[tmp++];
}
}
8. 计数排序
基本思想:
- 找出最大数
- 统计数组中每个值为i出现的次数,存入数组arrCount的第i项
- 对所有计数进行累加
- 将每个元素i放在目标数组的第(arrCount(i))项,每放一个元素就将arrCount(i)–
public void countSort(int[] arr){
int arrMax=findMax(arr);
int index=0;
int[] arrCount = new int[arrMax+1];
for (int i = 0; i < arr.length; i++) {
arrCount[arr[i]]++;
}
for (int i = 0; i < arrCount.length; i++) {
while (arrCount[i] > 0) {
arr[index++]=i;
arrCount[i]--;
}
}
}
public int findMax(int[] arr){
int max=0;
for (int i : arr ) {
if (i>max){
max=i;
}
}
return max;
}
9. 基数排序
基本思想:
- 取得数组中的最大数,并且取得最大数的位数;
- 从原始数组最低位开始以每个数的【位】(个十百~~)进行分组成radix数组;
- 对radix数组进行计数排序
算法如下:
public class RadixSort {
/**
* @Description 进位值
**/
final int MOD = 10;
public void radixSort(int[] arr) {
//获取最大位数对应值
int maxBit = maxBit(arr);
//代表位数对应的数1,10,100,,,
int mod = 1;
//保存每一位排序后的结果用于下一位的排序输入
int index = 0;
//排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里
int[][] bucket = new int[MOD][arr.length];
//用于保存每个桶里有多少个数字(10个桶)10进制
int[] order = new int[MOD];
while (maxBit > mod) {
//将数组arr的每个数放在对应桶里
for (int num : arr) {
int digit = (num / mod) % 10;
bucket[digit][order[digit]] = num;
order[digit]++;
}
//将桶里的数据覆盖到原数组中用于保护这一位的排序结果
for (int i = 0; i < MOD; i++) {
//桶里有数据,则从上到下遍历这个桶数据保存到原数组
if (order[i] != 0) {
for (int j = 0; j < order[i]; j++) {
arr[index] = bucket[i][j];
index++;
}
}
order[i] = 0;
}
mod *= MOD;
index = 0;
}
}
/**
* @Description 获取数组中的最大位数对应值
* @Param int[] arr
* @Return int maxBit 最大位数对应值 1 10 100 ,,,
**/
public int maxBit(int[] arr) {
int maxData = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > maxData) {
maxData = arr[i];
}
}
int maxBit = 1;
while (maxData >= MOD) {
maxData /= MOD;
maxBit *= 10;
}
return maxBit;
}
}
10. 桶排序
基本思想:
1.找出数组中的max、min
2.使用 动态数组ArrayList 作为桶,桶里放的元素也用 ArrayList 存储。桶的数量为(max-min)/arr.length+1
3.遍历数组 arr,计算每个元素 arr[i] 放的桶
4.每个桶各自排序
5.遍历桶数组,把排序好的元素放进输出数组
桶排序原文链接:https://blog.csdn.net/weixin_44026997/article/details/104330955
public void bucketSort(int[] arr) {
//计算最大值与最小值
// -2147483648
int max = Integer.MIN_VALUE;
//2147483647
int min = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
//计算桶的数量
int bucketNum = (max - min) / arr.length + 1;
ArrayList<ArrayList<Integer>> bucket = new ArrayList<>(bucketNum);
for (int i = 0; i < bucketNum; i++) {
bucket.add(new ArrayList<Integer>());
}
//将元素放入桶
for (int i = 0; i < arr.length; i++) {
int num = (arr[i] - min) / (arr.length);
bucket.get(num).add(arr[i]);
}
//每个桶进行排序
for (int i = 0; i < bucket.size(); i++) {
Collections.sort(bucket.get(i));
}
//将桶中元素赋值到原数组
int index = 0;
for (int i = 0; i < bucket.size(); i++) {
for (int j = 0; j < bucket.get(i).size(); j++) {
arr[index++] = bucket.get(i).get(j);
}
}
}
参考:
部分动图来源:https://www.cnblogs.com/onepixel/p/7674659.html
如有错误,欢迎留言!