数组
二分查找
二分查找要求数组排列时有序的
八种常见的排序
1.冒泡排序
2.选择排序
3.插入排序
4.希尔排序
5.快速排序
6.归并排序
7.基数排序
8.堆排序
冒泡排序
排序原理:数组元素两两比较,交换位置,大元素往后放,那么经过一轮比较后,最大的元素就会出现在最大的索引处
public class ArrayDemo{
public static void main(String[] args){
int[] arr={24,69,80,57,13};
for(int j=0;j<arr.length-1;j++){
for(int i=0;i<arr.length-1-j;i++){
if(arr[i]>arr[i+1]){
int t=arr[i];
arr[i]=arr[i+1];
arr[i+1]=t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
选择排序
排序原理:从0索引处开始,依次和后面的元素进行比较,小的元素往前放,经过一轮比较后,最小的元素就出现在最小的索引处
public class ArrayDemo{
public static void main(String[] args){
int[] arr={24,69,80,57,13};
for(int index=0;index<arr.length-1;index++){
for(int i=1+index;i<arr.length;i++){
if(arr[index]>arr[i]){
int t=arr[index];
arr[index]=arr[i];
arr[i]=t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
插入排序
排序原理:直接插入排序是一种简单的排序方法,他的基本操作是将一个记录插入到长度为m的有序表中,使之还是保持有序
public class ArrayDemo{
public static void main(String[] args){
int[] arr={49,38,65,97,76,13,27};
//外层循环定义轮次
//方法一
/* for(int i=0;i<arr.length;i++){
int j=i;
while(j>0&&arr[j]<arr[j-1]){
int t=arr[j];
arr[j]=arr[j-1];
arr[j-1]=t;
j--;
}
}*/
//方法二
for(int i=0;i<arr.length;i++){
for(int j=i;j>0;j--){
if(arr[j]<arr[j-1]){
int t=arr[j];
arr[j]=arr[j-1];
arr[j-1]=t;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
希尔排序
希尔排序是对直接插入排序的一种优化,大大提高插入排序的执行效率
希尔排序又称缩小增量排序
基本思想:先将原表按增量ht分组,每个子文件按照直接插入法排序。同样,用下一个增量ht/2将文件再分为子文件,再直接插入法排序。直到ht=1时,整个文件排序完成
关键:选择合适的增量
直接插入排序就是增量为一的希尔排序
public class ArrayDemo{
public static void main(String[] args){
int[] arr={46,55,13,42,17,94,5,70};
shellSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void shellSort(int[] arr){
//定义增量
//第一次增量选取数组长度的一半,然后不断减半
/*for(int h=arr.length/2;h>0;h--){
for(int i=h;i<arr.length;i++){
for(int j=i;j>h-1;j-=h){
if(arr[j]<arr[j-h]){
int t=arr[j];
arr[j]=arr[j-h];
arr[j-h]=t;
}
}
}
}*/
//有一种效率更高的序列叫克努特序列
//根据克努特序列选取我们第一个增量
int jiange=1;
while(jiange<=arr.length/3){
jiange=jiange*3+1;
}
for(int h=jiange;h>0;h=(h-1)/3){
for(int i=h;i<arr.length;i++){
for(int j=i;j>h-1;j-=h){
if(arr[j]<arr[j-h]){
int t=arr[j];
arr[j]=arr[j-h];
arr[j-h]=t;
}
}
}
}
}
}
快速排序
分治方法:比大小,再分区
1.从数组中取出一个数作为基准数
2.分区:将比这个数大或者等于的数全部放到他右边,小于他的数放到他左边
3.对左右区间重复第二步,直到个区间只有一个数
实现思路:
挖坑填数
1.将基准数挖出形成第一个坑
2.由后向前找比他小的数,找到后挖出此数填到前一个坑中
3.由前向后找比他大或者等于的数,找到后挖出此数填到前一个坑中
4.再重复执行2.3两步
public class ArryDemo{
public static void main(String[] args){
int[] arr={10,3,5,6,1,0,100,40,50,8};
quickSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr,int start,int end){
if(start<end){
int index=getIndex(arr,start,end);
quickSort(arr,start,index-1);
quickSort(arr,index+1,end);
}
}
private static int getIndex(int[] arr,int start,int end){
int i=start;
int j=end;
int x=arr[i];
while(i<j){
//由后向前找比他小的数,找到后挖出此数填到前一个坑中
while(i<j&&arr[j]>=x){
j--;
}
if(i<j){
arr[i]=arr[j];
i++;
}
//由前向后找比他大或者等于的数,找到后挖出此数填到前一个坑中
while(i<j&&arr[i]<x){
i++;
}
if(i<j){
arr[j]=arr[i];
j--;
}
}
//将基准数挖出形成第一个坑
arr[i]=x;
return i;
}
}
归并排序
实现思路:假设初始序列有n个记录,则可以看成是n个有序的子序列,每个子序列长度为1,然后两两归并,得到n/2个长度为2或1的有序子序列,再两两归并。。。如此重复,直到得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序
public class ArryDemo{
public static void main(String[] args){
int[] arr={10,30,2,1,0,8,7,5,19,29};
chaifen(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void chaifen(int arr[],int startIndex,int endIndex){
//计算中间索引
int centerIndex=(startIndex+endIndex)/2;
if(startIndex<endIndex){
chaifen(arr,startIndex,centerIndex);
chaifen(arr,centerIndex+1,endIndex);
guiBing(arr,startIndex,centerIndex,endIndex);
}
}
public static void guiBing(int[] arr,int startIndex,int centerIndex,int endIndex){
//定义零时数组
int[] tempArr=new int[endIndex-startIndex+1];
//定义左边数组的起始索引
int i=startIndex;
//定义右边数组的起始索引
int j=centerIndex+1;
//定义零时数组的起始索引
int index=0;
//比较左右两边数组元素的大小,往临时数组中放
while(i<=centerIndex&&j<=endIndex){
if(arr[i]<=arr[j]){
tempArr[index]=arr[i];
i++;
}else{
tempArr[index]=arr[j];
j++;
}
index++;
}
//处理剩余元素
while(i<=centerIndex){
tempArr[index]=arr[i];
i++;
index++;
}
while(j<=endIndex){
tempArr[index]=arr[j];
j++;
index++;
}
for(int k=0;k<tempArr.length;k++){
arr[k+startIndex]=tempArr[k];
}
}
}
基数排序
由于略有区别,这里就先不过多介绍,下次再补!
堆排序
堆排序是利用堆这种数据结构设计出的一种排序算法,堆排序是一种选择排序
堆排序的基本思想:
1.将待排序序列构造成一个大顶堆,此时,整个序列最大值是堆顶的根节点。
2.将其与尾部元素交换,此时尾部就为最大值
3.然后将剩余n-1个元素重新构造为一个堆,这样就会得到n个元素的次小值
4.如此反复执行,便得到一个有序序列
升序排列使用大顶堆,降序排列使用小顶堆
我们用简单的公式来描述一下堆的定义就是:
左节点 右节点
大顶堆:arr[i]>arr[2i+1]&&arr[i]>=arr[2i+2]
小顶堆:arr[i]<arr[2i+1]&&arr[i]<=arr[2i+2]
public class ArryDemo{
public static void main(String[] args){
int[] arr={1,0,6,7,2,3,4};
//定义开始调整位置
int startIndex=(arr.length-1)/2;
//循环开始
for(int i=startIndex;i>=0;i--){
toMaxHeap(arr,arr.length,i);
}
System.out.println(Arrays.toString(arr));
//经过上面操着,已经将数组变为一个大顶堆,把根元素和最后一个元素进行调换
for(int i=arr.length-1;i>0;i--){
int t=arr[0];
arr[0]=arr[i];
arr[i]=t;
toMaxHeap(arr,i,0);
}
System.out.println(Arrays.toString(arr));
}
/**
*@param arr 要排序的数组
*@param size 调整元素的个数
*@param index 从哪里开始调整
**/
private static void toMaxHeap(int[] arr,int size,int index){
//获取左右结点的索引
int leftNodeIndex=index*2+1;
int rightNodeIndex=index*2+2;
//查找最大结点对应的索引
int maxIndex=index;
if(leftNodeIndex<size&&arr[leftNodeIndex]>arr[maxIndex]){
maxIndex=leftNodeIndex;
}
if(rightNodeIndex<size&&arr[rightNodeIndex]>arr[maxIndex]){
maxIndex=rightNodeIndex;
}
//调换位置
if(maxIndex!=index){
int t=arr[maxIndex];
arr[maxIndex]=arr[index];
arr[index]=t;
//调整完可能影响到下面的子树不是大顶堆,我们还需要继续再次调整
toMaxHeap(arr,size,maxIndex);
}
}
}