最近因为找实习,重新梳理了一遍数据结构中常用排序算法,仅供学习参考,如有不足之处,敬请指正。
目录
基本思路:将数组看成一个有序数组,一个无序数组
public static void insertSort(int[] arr){
//数组是空或者数组里面只有一个元素,没必要排序
if (null == arr || arr.length < 2){
return;
}
for(int i=1;i=0 && temp
public static void binaryInsertSort(int[] arr){
for(int i=1;ilow;j--){
arr[j]=arr[j-1];
}
arr[low]=temp;
}
}
}
基本思路:最小增量排序,原理:先将待排序的数组元素分成多分子序列,使得每个子序列的元素个数相对较少,然后对各个子序列分别进行直接插入排序,待整个待排序序列“基本有序后”,再对所有元素进行一次直接插入排序。
//增量设置:d1 = n/2,d2 = d1/2 ...
//举例一下:{9,8,7,6,5,4,3,2,1,0} 10个数,现分为5组(9,4),(8,3),(7,2),(6,1),(5,0),然后分别对每组进行直接插入排序得到:(4,9),(3,8),(2,7),(1,6),(0,5),再将这5组分为2组(4,3,2,1,0),(9,8,7,6,5)分别对这两组进行直插排序,得:(0,1,2,3,4),(5,6,7,8,9)最终有序。
public class Sort{
public static void shellSort(int arr[]){
int len=arr.length;
int i,j;
int h;
int temp;
for(h=len/2;h>0;h=h/2){
for(i=h;i=0 && arr[j-h]>temp){
arr[j]=arr[j-h];
j=j-h;
}
arr[j]=temp;
}
}
}
}
基本思路:每次比较相邻两个元素,如果它们的顺序错误就把它们交换
//第一层循环,总比较次数n-1:0-n~2(i //第二层循环,未归位的位置比较 基本思路:i和j,分别指向第一个和最后一个,i像后移动,j向前移动,选第一个数为标准(一般这样做,当然快排的关键就是这个“标准”的选取),从后面开始,找到第一个比标准小的数,互换位置,然后再从前面,找到第一个比标准大的数,互换位置,第一趟的结果就是标准左边的都小于标准,右边的都大于标准(但不一定有序),分成两拨后,继续递归的使用上述方法,最终有序! 基本思路: //首先找到数组中最小的那个元素,其次,将它和数组的第一个元素交换位置 //如果第一个元素就是最小元素,那么它就和自己交换。如果只剩下最后一个元素,就没必要排了,它就是最大的 //再次在剩下的元素中找最小的元素,将它与数组中的第二个元素交换。如此往复,直到将整个数组排序。 相关知识:完全二叉树:叶子结点只可能在层次最大的两层上出现.,并且最下面一层节点都集中在该层最左边的若干位置的二叉树。堆是具有如下性质的二叉树:每个结点的值都小于(大于)或等于其左右孩子结点的值,称为小(大)顶堆。 Ki<=K2i; Ki<=K2i+1 <<左移运算符,num << 1,相当于num乘以2 >>右移运算符,num >> 1,相当于num除以2 基本思路:对一组待排序记录的键值,首先把它们按照堆的定义排成一个堆,称这一过程为建堆。首先找到最小(大)键值,然后将最小(大)键值取出,用剩下的键值再建堆,取得次小(大)的键值。如此反复进行,直到得到最大(小)键值,从而将全部键值排好序为止。 堆排序分为三个过程: 1. 建堆:从一个数组顺序读取元素,建立一个堆(完全二叉树) 2. 初始化:将堆进行调整,使得堆顶为最大(最大堆)或者最小(最小堆)的元素 3. 维护:将堆顶元素出堆后,需要将堆的最后一个节点补充到堆顶,因为这样破坏了堆的秩序,所以需要进行维护。 基本思路:归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。 基本思路:对每一个输入的元素arr[i],确定小于 arr[i] 的元素个数。 算法流程(1) 需要三个数组: //待排序数组 int[] arr = new int[]{4,3,6,3,5,1}; //辅助计数数组 int[] help = new int[max - min + 1]; //该数组大小为待排序数组中的最大值减最小值+1 //输出数组 int[] res = new int[arr.length]; 1.求出待排序数组的最大值max=6, 最小值min=1 2.实例化辅助计数数组help,help数组中每个下标对应arr中的一个元素,help用来记录每个元素出现的次数 3.计算 arr 中每个元素在help中的位置 position = arr[i] - min,此时 help = [1,0,2,1,1,1]; (3出现了两次,2未出现) 4.根据 help 数组求得排序后的数组,此时 res = [1,3,3,4,5,6] 算法流程(2) 需要三个数组: //待排序数组 int[] arr = new int[]{4,3,6,3,5,1}; //辅助计数数组 int[] help = new int[max - min + 1]; //该数组大小为待排序数组中的最大值减最小值+1 //输出数组 int[] res = new int[arr.length]; 1.求出待排序数组的最大值max=6, 最小值min=1 2.实例化辅助计数数组help,help用来记录每个元素之前出现的元素个数 3.计算 arr 每个数字应该在排序后数组中应该处于的位置,此时 help = [1,1,4,5,6,7]; 4.根据 help 数组求得排序后的数组,此时 res = [1,3,3,4,5,6] 基本思路:将整数按位数切割成不同的数字,然后按每个位数分别比较。 具体做法:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。 桶排序可用于最大最小值相差较大的数据情况,比如[9012,19702,39867,68957,83556,102456]。 但桶排序要求数据的分布必须均匀,否则可能导致数据都集中到一个桶中。比如[104,150,123,132,20000], 这种数据会导致前4个数都集中到同一个桶中。导致桶排序失效。 基本思路:把数组 arr 划分为n个大小相同子区间(桶),每个子区间各自排序,最后合并。 计数排序是桶排序的一种特殊情况,可以把计数排序当成每个桶里只有一个元素的情况。 算法流程: 1.找出待排序数组中的最大值max、最小值min 2.我们使用 动态数组ArrayList 作为桶,桶里放的元素也用 ArrayList 存储。桶的数量为(max-min)/arr.length+1 3.遍历数组 arr,计算每个元素 arr[i] 放的桶 4.每个桶各自排序 5.遍历桶数组,把排序好的元素放进输出数组 参考博客: https://www.cnblogs.com/bjh1117/p/8335628.htmlpublic class bubbleSort{
public static void bubbleSort(int[] array){
if(null=array || array.length < 2){
return;
}
for(int i=0;i
快速排序
//快速排序
//定义一个阈值,分别从最左面和最右面向中间遍历元素,左面找到一个大于阈值的数据便停止,
//右边找到一个小于阈值的数据便停止,如果此时左右两边都还没有走到中间,
//则交换左面大于阈值的数据和右面小于阈值的数据;重复上述过程,直到左面指针和右面指针相遇,
//此时左面数据均小于阈值,右面数据均大于阈值,划分结束。划分结束后,数据仍然是无序的,
//但更接近于有序。
public class quickSort{
public static void sort(int arr[],int low,int high){
int i,j;
int index;
if(null=arr||low>=high)
return;
i=low;
j=high;
index=array[i];
while(i
选择排序
简单选择排序
public static void selectSort(int[] arr) {
//数组是空或者数组里面只有一个元素,没必要排序
if (null == arr || arr.length < 2)
return;
//最后一个元素没必要再给它排序,因为它就是最大的
for (int i = 0; i < arr.length - 1; i++) {
//初始的时候就认为最小值索引指针在i位置,最小值就是arr[i]
int minIndex = i;
//在I后面[i+1,arr.length-1]区间找最小的值
for (int j = i + 1; j < arr.length; j++) {
//找到就把最小值索引更新,找不到最小值索引还在原位
minIndex = arr[j] < arr[minIndex] ? j : minIndex;
}
//将i位置上的元素值和最小索引位置的元素值交换
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
堆排序
public class HeapSort{
public static int[] sort=new int[] {1,0,10,20,3,5,6,4,9,8,12,17,34,11};
public static void main(String[] args){
buildMaxHeapify(sort);
heapSort(sort);
}
public static void buildMaxHeapify(int[] arr){
int startIndex=getParentIndex(arr.length-1);
for(int i=startIndex;i>=0;i--){
maxHeapify(arr,arr.length,i);
}
}
public static void maxHeapify(int[] arr,int heapSize,int index){
int left=getChildLeftIndex(index);
int right=getChildRightIndex(index);
int largest=index;
if(left
其他排序
归并排序
public class Sort{
public static void Merge(int arr[],int p,int q,int r){
int i,j,k,n1,n2;
n1=q-p+1;
n2=r-q;
int[] L=new int[n1];
int[] R=new int[n2];
for(i=0,k=p;i
计数排序
所以可以直接把 arr[i] 放到它输出数组中的位置上。假设有5个数小于 arr[i],所以 arr[i] 应该放在数组的第6个位置上。public static int[] countSort1(int[] arr){
if (arr == null || arr.length == 0) {
return null;
}
int max = Integer.MIN_VALUE;
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 help[] = new int[max];
//找出每个数字出现的次数
for(int i = 0; i < arr.length; i++){
int mapPos = arr[i] - min;
help[mapPos]++;
}
int index = 0;
for(int i = 0; i < help.length; i++){
while(help[i]-- > 0){
arr[index++] = i+min;
}
}
return arr;
}
public static int[] countSort2(int[] arr){
int max = Integer.MIN_VALUE;
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[] help = new int[max - min + 1];
//找出每个数字出现的次数
for(int i = 0; i < arr.length; i++){
int mapPos = arr[i] - min;
help[mapPos]++;
}
//计算每个数字应该在排序后数组中应该处于的位置
for(int i = 1; i < help.length; i++){
help[i] = help[i-1] + help[i];
}
//根据help数组进行排序
int res[] = new int[arr.length];
for(int i = 0; i < arr.length; i++){
int post = --help[arr[i] - min];
res[post] = arr[i];
}
return res;
}
基数排序
public class RadixSort {
/*
* 获取数组a中最大值
*
* 参数说明:
* a -- 数组
* n -- 数组长度
*/
private static int getMax(int[] a) {
int max;
max = a[0];
for (int i = 1; i < a.length; i++)
if (a[i] > max)
max = a[i];
return max;
}
/*
* 对数组按照"某个位数"进行排序(桶排序)
*
* 参数说明:
* a -- 数组
* exp -- 指数。对数组a按照该指数进行排序。
*
* 例如,对于数组a={50, 3, 542, 745, 2014, 154, 63, 616};
* (01) 当exp=1表示按照"个位"对数组a进行排序
* (02) 当exp=10表示按照"十位"对数组a进行排序
* (03) 当exp=100表示按照"百位"对数组a进行排序
* ...
*/
private static void countSort(int[] a, int exp) {
//int output[a.length]; // 存储"被排序数据"的临时数组
int[] output = new int[a.length]; // 存储"被排序数据"的临时数组
int[] buckets = new int[10];
// 将数据出现的次数存储在buckets[]中
for (int i = 0; i < a.length; i++)
buckets[ (a[i]/exp)%10 ]++;
// 更改buckets[i]。目的是让更改后的buckets[i]的值,是该数据在output[]中的位置。
for (int i = 1; i < 10; i++)
buckets[i] += buckets[i - 1];
// 将数据存储到临时数组output[]中
for (int i = a.length - 1; i >= 0; i--) {
output[buckets[ (a[i]/exp)%10 ] - 1] = a[i];
buckets[ (a[i]/exp)%10 ]--;
}
// 将排序好的数据赋值给a[]
for (int i = 0; i < a.length; i++)
a[i] = output[i];
output = null;
buckets = null;
}
/*
* 基数排序
*
* 参数说明:
* a -- 数组
*/
public static void radixSort(int[] a) {
int exp; // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...
int max = getMax(a); // 数组a中的最大值
// 从个位开始,对数组a按"指数"进行排序
for (exp = 1; max/exp > 0; exp *= 10)
countSort(a, exp);
}
public static void main(String[] args) {
int i;
int a[] = {53, 3, 542, 748, 14, 214, 154, 63, 616};
System.out.printf("before sort:");
for (i=0; i
桶排序
//桶排序
public static void bucketSort(int[] arr){
int max = Integer.MIN_VALUE;
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
https://blog.csdn.net/zhangerqing/article/details/8831542
https://segmentfault.com/a/1190000013967025(希尔排序)
https://www.cnblogs.com/zer0Black/p/6169858.html(计数排序、桶排序)