排序笔记
此笔记用来记录排序种类,增加熟练度
冒泡排序
思路:每次选择出最大或者最小的“冒泡”至最后位置(也可以最前位置)以达到排序效果。
下面以从小到大排序为例
public void bubble(int [] a){
int len = a.length;
for(int i=0;i<len-1;i++){
for(int j=0;j<len-i-1;j++){
if(a[j]>a[j+1]){
int tem = a[j];
a[j] = a[j+1];
a[j+1] = tem;
}
}
}
}
i 标记已比较过的个数,j 根据 i 缩小需要比较的范围,同时需要考虑下标越界问题
选择排序
思路:将数组划分为 a 已比较部分 b 未比较部分,每次从未比较部分选出最大/小的数,放到已比较部分的末尾/头部
下面以从小到大为例
public void select(int[] a ){
int len = a.length;
int minindex ;
for(int i=0;i<len-1;i++){
minindex=i;//重置最小值的位置,最后一次比较时,a[i-2]与a[i-1]比较
for(int j=i+1;j<len;j++){
if(a[minindex]>a[j])
minindex=j;
}
int tem = a[i];
a[i] = a[minindex];
a[minindex] = tem;
}
}
插入排序
思路:以从小到大为例,将数组划分为a 已比较部分 b 未比较部分,每次从未比较部分的末尾取出一个数x与a部分从后往前比较,如果x小于a中的数a[i],则a中的数顺次后移,否则插入至a[i]右边
public void insertSort(int[] a){
int len = a.length;
int preIndex ,current;
for(int i=1;i<len;i++){
preIndex = i-1;
current = a[i];
while(preIndex>=0 && a[preIndex]>current){
a[preIndex+1]=a[preIndex];
preIndex--;
}
a[preIndex+1]=current;
}
}
希尔排序
思路:是普通插入排序的改良版,分割若干子序列,分别进行插入排序,具体算法描述
- 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
- 按增量序列个数k,对序列进行k 趟排序;
- 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
代码实现:
public void shell(int [] arr, int gap){
int len = arr.length;
while(gap>0){
for(int i=gap;i<len;i++){
int preIndex = i-gap;
int current = arr[i];
while(preIndex>=0 && arr[preIndex]>current){
arr[preIndex+gap]=arr[preIndex];
preIndex-=gap;
}
arr[preIndex+gap]=current;
}
gap = (int)Math.floor(gap/2);
}
}
归并排序
思路:将数组不断地分为左右两部分直至最小,排序后再依次合并的过程
代码
public void mergeSort(int[] arr) {
sort(arr, 0, arr.length-1);
}
public void sort(int[] arr, int L, int R){
if(L==R)
return ;
int mid = (L+R)>>1;
sort(arr, L, mid);
sort(arr, mid+1, R);
merge(arr, L, R, mid);
}
public void merge(int []arr,int L, int R, int mid){
int [] tem = new int[R-L+1];
int p1 = mid+1;
int p2=L;
int i=0;
while(p1<=R && p2<=mid){
tem[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while(p2<=mid){
tem[i++] = arr[p2++];
}
while(p1<=R){
tem[i++] = arr[p1++];
}
for(i =0; i<tem.length;i++){
arr[L+i] = tem[i];//L+i顺次合并
}
}
快速排序
思路:选择一个基准位,经过排序,使基准位左边的数都比基准位小,右边的数都比基准位大,然后递归的排出有序序列。
代码:
public void main(int[] arr) {
arr = quickSort(arr, 0, arr.length-1);
}
public int[] quickSort(int []arr, int left, int right){
if(left<right){
int position = getPosition(arr, left, right);
quickSort(arr, left, position-1);
quickSort(arr, position+1, right);
}
return arr;
}
public int getPosition(int []arr, int left, int right){
int pivot = left;
int index = pivot+1;
for(int i=index; i<=right; i++){
if(arr[i]<arr[pivot]){
swap(arr, i, index);
index ++;
}
}
swap(arr, pivot,index-1);
return index-1;
}
public void swap(int []arr, int i, int j){
int tem = arr[i];
arr[i] = arr[j];
arr[j] =tem;
}
堆排序
思路:利用大根堆的性质,每次将最大元素与堆尾元素交换,然后刨除最大元素,将剩余元素重新进行调整,形成新的大根堆,依次操作得出数组的排序结果。其中需要了解的是,堆是完全二叉树,完全二叉树A的左子节点为2A+1,右子节点为2A+2
代码:
public void HeapSort(int[] arr) {
int len = arr.length;
createHeap(arr, len);
for(int i= arr.length-1;i>0;i--){
swap(arr, 0, i);
len--;
heapify(arr,0,len);//对剩余元素重新调整
}
}
public void createHeap(int[] arr,int len){
for(int i=(int)Math.floor(len/2);i>=0;i--){
heapify(arr, i, len);
}
}
public void heapify(int[] arr, int i, int len){
int left = i*2+1;
int right = i*2+2;
int largeIndex = i;
if(left<len && arr[left]>arr[largeIndex]){
largeIndex=left;
}
if(right<len && arr[right]>arr[largeIndex]){
largeIndex=right;
}
if(largeIndex!=i){
swap(arr, i, largeIndex);
heapify(arr, largeIndex, len);//递归调用,对largeIndex节点后的子树都进行调整
}
}
public void swap(int[] arr, int i, int j){
int tem = arr[i];
arr[i] = arr[j];
arr[j] = tem;
}
计数排序
思路:计数排序假定待排序的数是0-k之间的数,然后构建一个数组bucket,其中bucket[i]存放的是待排序数组中 i 出现的次数,然后再将i根据次数顺次放回至原数组,达到排序的目的
代码:
public void main(int[] arr) {
countSort(arr, getMaxValue(arr));
}
public void countSort(int[] arr, int maxValue){
int[] bucket = new int[maxValue+1];
for(int value:arr){
bucket[value]++;
}
int i=0;
for(int j=0;j<bucket.length;j++){
while(bucket[j]>0){
arr[i++]=j;
bucket[j]--;
}
}
}
public int getMaxValue(int[] arr){
int maxValue = arr[0];
for(int value:arr){
if(value>maxValue)
maxValue=value;
}
return maxValue;
}