1、选择排序( 时间复杂度O(n2))
思想:数组中的每个数和第一个数进行比较,小于第一个数,就交换位置,每轮产生一个最小的数在最左侧。
for(int i=0;i<array.length-1;i++){
for(int j=i+1;j<array.length;j++){
if array[j]>array[i]:swap();
}
}
————————————————————————————————————————————
2、冒泡排序 O(n2)
思想:从第一个数开始,每次和右边的数进行比较,较小的数放左边,较大的数放右边,依次比较,第一轮产生一个最大的数,放在最后位置。第二轮重复,产生倒数第二大的数,放在倒数第二大的位置。
for(int i=0;i<array.length-1;i++){
for(int j=0;j<array.length-1-i;j++){
if array[j]>array[j++] :swap()
}
}
————————————————————————————————————————————
3、插入排序 O(n2)
思想:将数组分成左右两部分,左部分的所有元素跟右部分第一个元素k进行比较,大于k就交换,直到k左边比k小,右边比k大,k的位置确定,继续右移,每轮确定一个数位置
for(int i=1;i<array.length;i++){
for(int j=i-1;j>=0;j--){
if (array[i]<array[j]) :swap();
}
}
————————————————————————————————————————————
4、归并排序 O(nlog2n)
思想: ①先将数组每次从中间一份为二,递归拆分直至成单一数据 (此过程称为拆分)
②再复制出一个新的数组temp,比较左右两边数组,左边数组从l开始,右边数组从mid+1开始
③依次遍历左右两边数组,取最小的数放入temp
④temp数组放入array数组,直至所有拆分的数组遍历完成 (此过程称为归并)
public static void process(int[] array,int left,int right) {
if(left == right) :return ;
int mid = left + ((right - left)>>1);//取中间值
process(array,left,mid); //遍历拆分左侧
process(array,mid+1,right);//遍历拆分右侧
merge(array,left,mid,right);//归并
}
public static int[] merge(int[] array,int left,int mid,int right) {
int[] temp =new int[array.length];//创建临时数组
int l = 0; r = mid+1; i = 0;
while(l<=left && r<=right) { //当左 右数组都有值时,取每次遍历取最小值放入temp里
temp[i++] = array[l]<array[r]?array[l++]:array[r++];
}
while(l<=left) { //当只有左边数组有值时,将左边数组值全部放入temp里
temp[i++] = array[l++];
}
while(r<right) { //当只有右边数组有值时,将右边数组值全部放入temp里
temp[r++] = array[r++];
}
for(int p = 0;p<temp.length ; p++) { //将temp数组的数放入array里
array[l+p] = temp[p];
}
return array;
}
————————————————————————————————————————————
5、堆排序 O(nlog2n)
思想:将数组想象成一个二叉树,i是下标,根节点是(i-1)/2,左节点是2i+1,右节点2i+2
大根数:树上的根节点都大于子节点。 首先将数组调整为大根树,这个过程叫做heapInsert
①此时最上面根节点为数组的最大数K,将最大数K与数组最后一个数交换,并断交,K位置确定
②来到最上面根节点的数P,与子节点最大的数做交换,一直遍历子节点,并与最大子节点交换,直到没有子节点,停止 (此步骤的目的是为了保证每次都是大根树)
③重复步骤①最上面根节点与最后一个数交换,并断交
步骤①~步骤②称为heapfy
heapInsert过程:
public static void heapInsert(int[] array) {
for(int i=0;i<array.length;i++) {
while ((i-1)/2>= 0 && array[i]>array[(i-1)/2] ) { //当前节点一直跟父节点比较
swap(array,i,(i-1)/2);
i = (i-1)/2;
}}
heapfy过程:
public static void heapfy(int[] array,int length) {
for(int i = 0;i<length;i++) {//遍历每一个节点
int left = 2*i+1;//找到该节点的左节点
int right = 2*i+2;//找到该节点的右节点
while(left < length) {
int larger = (right<length) &&(array[left]<array[right])? right:left; //找到左右中最大的那个节点
if (i == larger ){ break;};
if(array[i]< array[larger]) {//当前节点跟最大的节点进行比较,若当前节点小于 较大的子节点
swap(array, i,larger); //交换
i = larger; //当前节点来到 较大的子节点
}
left = 2*i+1; //再找到较大子节点的左节点,继续
right = 2*i+2;//再找到较大子节点的右节点,继续
}} }
————————————————————————————————————————————
6、快排 O(nlog2n)
思想:①随机选择一个数K,将数组分为小于K区域less,大于K区域more,则K的位置确定。 ②在小于K区域里继续选择一个数K2,继续划分出小于K2区域,大于K2区域,确定k2位置。
③右侧大于K区域more,同理递归操作
if(l == r) return ;
int k = array[(int)(Math.random()*(r-l))+l];
int index = 0;more = r; less = index-1;
while(index < more) {
if (array[index]<k) : swap(array,++less,index++);
else if(array[index]>k):swap(array,--more,index);
}else :index++;
}
sort(array,l,less+1);
sort(array,more,r);
————————————————————————————————————————————
7、荷兰国旗问题
问题:给定一个乱序数组,一个特定数字K,将小于K的数放在左侧,大于K的数放在右侧,等于K的数放在中间,并返回左侧最大位置和右侧最小位置
思想:①将数组array想象成三段,less区域 array more区域,less区域全部为小于K的数,more区域全部为大于K的数。起始位置,less=-1.more=length
②遍历array,若array[i]< k:array[i]与less下一个数做交换,并且less+1,i+1。此时less就包含了一个小于K的数字
③若array[i]>k:more先减一,array最后一个数字位置,array[i]与more的位置做交换,i不变。此时more就包含了一个大于K的数字
④若array[i]=k:i+1,跳到下一个
⑤遍历步骤②~④,保证less只想小于K数的最后一个位置,more只想大于K数的第一个位置
public static int[] sort(int[] array,int k) {
int index = 0; more = array.length; less = index-1;
while(index < more) {
if (array[index]<k) :swap(array,++less,index++);
else if(array[index]>k) :swap(array,--more,index);
else : index++;
}
return new int[]{less,more};
————————————————————————————————————————————
8、计数排序
计数排序,基于位数的词频统计
1、准备一个辅助数组,用来统计源数组数字出现的次数。
2,统计完后,遍历辅助数组,根据词频写入到源数组
public static void sort(int[] array) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for(int a : array) {
max = Math.max(max, a);
min = Math.min(min, a);
}
int[] temp = new int[max-min+1];
for(int i=0;i<array.length;i++) {
int index = array[i]-min;
temp[index]++ ;
}
int k=0;
for(int i = 0 ; i <temp.length;i++) {
while (temp[i]>0) {
array[k++]=i+min;
temp[i]--;
}}
————————————————————————————————————————————
9、基数排序
* 桶排序
* 1、找到数组中最大数的位数
* 2、创建用于装按位数排好序的数组
* 3、取每个数的个位数字、十位数子、百位数字,按词频装入数组中
* 4、将词频数组中,每个数前面的数词频相加
* 5、根据数字在词频数组中的位置,放置
* 6、依次排好个位、十位、百位
public static void bucketSort(int[] array,int l,int r,int digit) {
final int radix = 10;int i = 0 ,j = 0;
int[] bucket = new int[r-l+1];//用于装按位数排好序的数组
for(int d =1;d<= digit;d++) {
int[] count = new int[radix]; //创建一个0~9的数组
for( i=l ;i <=r;i++) {
j = getDigit(array[i],d);//取每个数的个位数字、十位数子、百位数字。。。
count[j]++ ;//个位数字的数 词频加1
}
for(i = 1 ;i<radix ; i++) {
count[i] = count[i]+count[i-1]; //每个数前面数的词频数字相加
}
for(i=r ; i>=l ; i--) {
j = getDigit(array[i],d);//取个位上的数
bucket[count[j]-1] = array[i];//根据词频数组中数字出现的次数,放入桶中
count[j]--;//词频数组中该数的词频减一 }
for(i=l,j=0;i<=r;i++,j++) {
array[i] = bucket[j];
} } }
—————————————————————————————————————