算法——排序

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];

} } }

—————————————————————————————————————

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值