以升序为例——
1.选择排序
首先在待排序的序列中找到最小元素,存放在待排序序列的起始位置;然后,从剩下的待排序序列中继续寻找最小元素,放在已排序序列的末尾。以此类推,直到所有的元素排序完毕。
void SelectSort(int a[], int len)
{
for(int i=0; i<len-1;i++)//i代表了已排序序列中的元素个数
{
for(int j=i+1; j<len;j++)//寻找待排序序列中最小元素的过程
{
if(a[i]>a[j]) a[i]<————>a[j];
}
}
}
2.冒泡排序
冒泡的含义——越大的元素会经由交换慢慢浮到数列末端。
重复地走访要排序的序列,一次比较相邻的两个元素,若大小与顺序不符就交换,每轮走访后都可以将当前前排最大的数提取出来。
void BubbleSort(int a[], int len)
{
for(int i=0;i<len;i++)
{
for(int j=0;j<len-1-i;j++)
{
if(a[j]>a[j+1]) a[j]<————>a[j+1];//把较大的值往后推,第一轮结束后最后一个值是最大的。
}
}
}
3.插入排序
从数组的第2个值开始往前遍历,如果比前置位的值小,则自己必然要插入到前面已排序序列中的某一个位置?哪个位置?由于数组不能直接增减元素个数,故必须通过邻近比较、数组值挪位,来最终确定自己的插入位置。——每次遍历,遍历位置以前序列都是排好的。
void insertSort(int a[],int len)
{
for(int i=1; i<len; i++)
{
if(a[i]<a[i-1])
{
int j; int temp = a[i];//由于数组通过覆盖来更新,故先记录下当前需要插入到前排的值
for(j=i-1; j>=0 && a[j]>temp; j--)
{
a[j+1]=a[j];//寻找待插入的位置,如果不是,前面的值就依次挪位;如果是,则跳出循环
}
a[j+1]=temp;
}
}
}
4.快速排序
定义两个指针分别指向待排序序列的首尾,确定一个基准值(一般为待排序序列的第一个值),每一轮比较过后,基准值前面的数都比其小,后方的数都比其大。于是原序列被拆分成了两个小的待排序序列,以此递归,最终实现排序。
找到一个比较好理解的博文:https://blog.youkuaiyun.com/nrsc272420199/article/details/82587933
具体的过程如下:
public static void quickSort(int[] A, int low, int high)
{
if(low<high)
{
int index = getIndex(A,low,high);
quickSort(A,low,index-1);//递归查找
quickSort(A,index+1,high);
}
}
public static int getIndex(int[] A, int l, int h)
{
int base = A[l];
while(l<h)
{
while(l < h && A[h]>=base)//h指向的值往前挪,直到找到比基准数小的值。
{
h--;
}
A[l]=A[h];//比基准数小的值赋给l所指向的数组位置
while(l < h && A[l]<=base)//l指向的值往后挪,直到找到比基准数大的值。
{
l++;
}
A[h]=A[l];//比基准数大的值赋给h所指向的数组位置
}
A[h] = base;
return h;
}
5.希尔排序
也称缩小增量排序,是插入排序的改进,将数组分为若干个小数组进行插入排序,逐渐合并成原数组。
public static void shellSort(int[] A, int delta)
{
int increasement = A.length;
do
{
increasement = (increasement+1)/delta;//初始每个小序列的元素个数为delta,序列总数为increasement个
for(int i=0; i<increasement; i++)//遍历每个小序列,一共increasement个
{
//下面是插入排序的操作,注意:每个小序列的第2个元素开始,往前遍历,增量不是1,是increasement
for(int j=i+increasement; j<A.length ; j+=increasement)
{
if(A[j]<A[j-increasement])
{
int k;
int temp=A[j];
for(k=j-increasement; k>=0 && A[k]>temp ;k-=increasement)
{
//循环移动覆盖数组值
A[k+increasement]=A[k];
}
A[k+increasement]=temp;
}
}
}
}
while (increasement>1);
}
6.堆排序
利用二叉树的性质。
a.对数组进行二叉树排列,循环遍历每个非叶子节点,若发现子节点的数比自己大,则记录较大值位置max,然后交换两个数的位置,并对发生交换的子节点进行递归,以调整后续的节点相对位置。
b.每一轮遍历,都会把当前的最大值调整到栈顶,因此把栈顶元素与待排序序列的最后一个位置元素相交换。再把需要比较的节点总数减1,继续下一轮遍历。
c.遍历所有轮数结束后,即排序结束。
public static void heapAdjust(int[] Arr, int i ,int size) //size是要比较的节点总数
{
int max = i;
int left = 2*i+1;
int right = 2*i+2;
if(left<size && Arr[left]>Arr[max])
max = left;
if(right<size && Arr[right]>Arr[max])
max = right;
if(max != i)
{
int temp;
temp = Arr[max];
Arr[max] = Arr[i];
Arr[i] =temp;
heapAdjust(Arr,max,size);
}
}
public static void heapSort(int[] Arr, int size)
{
for(int i=(size-1)/2; i>=0; i--)//循环完成一次,堆排序排完一次,都把最大值放在根节点位置上了
{
heapAdjust(Arr,i,size);
}
//把根节点上的那个最大值放到堆顶,对除堆顶外的剩余元素继续进行堆排序,要比较的节点总数是递减的size是要递减的
if(size>0)
{
int temp;
temp = Arr[0];
Arr[0] = Arr[size-1];
Arr[size-1] = temp;
heapSort(Arr,--size);
}
}
7.归并排序
递归——对整个待排序序列不断递归分解成两份,直至每份小序列只有1个数;
和并——从最小的序列开始,不断排序合并,每次合并后的这部分序列都是有序的。
public static void mergeSort(int[] Arr, int left, int right )
{
if(left<right)
{
int mid = left+(right-left)/2; //防止溢出
mergeSort(Arr,left,mid); //当l和r相差1时,此操作使得两者会相等,只剩一个数,无需再递归,开始合并。否则陷入死循环……
mergeSort(Arr,mid+1,right);
merge(Arr,left,mid,right);
}
}
public static void merge(int[] Arr,int left, int mid, int right) //合并操作,针对两个有序序列(把一个序列看成两部分)(l,m)(m+1,r)
{
int i = left;
int j = mid+1;
int k = 0;
int[] temp = new int[right-left+1];
while(i<=mid && j<=right) //循环比较两个序列中的较小值,此循环直接完成min(m,n)个元素的合并
{
if(Arr[i]<Arr[j])
temp[k++] = Arr[i++];
else
temp[k++] = Arr[j++];
}
while(j<=right) //m<n
{
temp[k++] = Arr[j++];
}
while(i<=mid) //m>n
{
temp[k++] = Arr[i++];
}
//把temp的值重新赋给Arr数组
for(int p=0; p<temp.length; p++)
{
Arr[p+left] = temp[p];
}
}
8.计数排序
public static int[] countingSort(int[] Arr)
{
int len1= Arr.length;
int max = getMax(Arr);
int min = getMin(Arr);
int len2 = max-min+1;
int[] countArr = new int[len2];
int[] result = new int[len1];
int index;
//第一次转变,负数变正数的同时,键值变索引,记录元素出现次数
for(int i= 0; i<len1; i++)
{
countArr[Arr[i]-min]++;
}
//第二次转变,元素累计出现次数
for(int i=1; i<len2; i++)
{
countArr[i] += countArr[i-1];
}
//根据Arr[i]的值,确定countArr[Arr[i]]的值A,再把countArr[A]的值存到result中,
for(int i=len1-1; i>=0; i--)
{
index = countArr[Arr[i]-min];
result[index-1] = Arr[i];
countArr[Arr[i]-min]--;
}
return result;
}