冒泡排序
对一个含有N个元素的数组,进行排序时,最少需要一次循环,最多需要经过N-1次循环;
需要两个for循环和一个判断条件;
第一轮结束,就可以在末尾得到最小或最大值;
public void maoPao(){
int[] arr=new int[5,78,9,20,7,1,60];
for(int len = arr.length-1; i>0; i--){//每轮遍历次数比上一次要少1
for(int j=0;j<len;j++){
//如果前一个数大于下一个数,就交换
if(arr[j] > arr[j+1]){//如果是降序,就把 > 改为 <
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
//优化:若数组就是有序排列的,则最少只需一次循环;
public void maoPao1(){
int[] arr=new int[5,7,9,20,78,99];
for(int len = arr.length-1; i>0; i--){//每轮遍历次数比上一次要少1
//判断是否进行过交换操作;
boolean sorted = true;
for(int j=0;j<len;j++){
//如果前一个数大于下一个数,就交换
if(arr[j] > arr[j+1]){//如果是降序,就把 > 改为 <
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
sorted = false;
}
}
//当某一次遍历完,发现一次交换操作都没有,则表示数组就是有序排列的;则就结束;
if(sorted){
break;//结束循环;
}
}
}
选择排序
核心原理:不断从数组中找出最大值,然后把最大值放入末尾;
需要两个for循环、一个判断条件、一个index;
public void xuanZe(){
int[] arr=new int[5,78,9,20,7,1,60];
for(int i = arr.length-1; i>0; i--){//每轮遍历次数比上一次要少1
int maxIndex=0;
for(int j=0;j<i;j++){
//如果前一个数大于下一个数,就记录最大值的下标
if(arr[maxIndex] < arr[j+1]){
maxIndex = j+1;
}
}
int max = arr[maxIndex];
arr[maxIndex] = arr[i];
arr[i] = max;
}
}
插入排序
原理:从数组中获取一个数,并和其他数比较,选择合适的位置插入;
需要2个循环、一个判断条件、一个要对比的元素cur;
public void chaRu(){
int[] arr=new int[5,78,9,20,7,1,60];
for(int i = 0; i< arr.length-1; i++){
int pre = i;
int cur = arr[pre+1];
while(pre >=0 && cur <arr[pre]){
arr[pre+1]=arr[pre];
pre--;
}
arr[pre+1]=cur;
}
}
希尔排序
原理:每次将数组按步长step分为N行的矩阵;每列进行插入排序;直到步长为1;
需要3个循环: 一个步长循环,一个插入排序算法;
原数组 [2,6,19,28,3,7,10,22,18]
步长数组:长度/2 ; steps=[4,2,1];
第1次步长4:
[2, 6, 19, 28]
[3, 7, 10, 22]
[18]
每列进行插入排序:
[2, 6, 10, 22]
[3, 7, 19, 28]
[18]
结果:
[2, 6, 10, 22, 3, 7, 19, 28,18]
第2次步长2:
[2, 6]
[10, 22]
[3, 7]
[19, 28]
[18]
每列进行插入排序:
[2, 6]
[3, 7]
[10, 22]
[18, 28]
[19]
结果:
[2, 6, 3, 7, 10, 22, 18, 28,19]
第3次步长1:
[2]
[6]
[3]
[7]
[10]
[22]
[18]
[28]
[19]
每列进行插入排序:
[2]
[3]
[6]
[7]
[10]
[18]
[19]
[22]
[28]
结果:
[2, 3, 6, 7, 10, 18, 19, 22,28]
private int[] array = {12,20,30,3,6,22,55,100};
//获取步长数组
private List<Integer> shellSequence(){
List<Integer> sequence = new ArrayList<>();
int step = array.length;
while ((step = step>>1) > 0){
sequence.add(step);
}
return sequence;
}
public void paixu(){
List<Integer> sequence = shellSequence();
for(Integer step: sequence){
shellByStep(step);
}
}
private void shellByStep(int step) {
int cur = 0;
int j = 0;
// 第一次 step =4
for(int i= step;i<array.length;i++){
cur = array[i]; // 这里的cur = 6;
for(j=i-step;j>=0;j-=step){
int a = array[j];
if(cur < a){ // 如果拿出来对比的数据 比已经存在的某个数据小
array[j+step] = array[j];
}else{ //直接跳出循环
break;
}
}
array[j+step] = cur;
}
}
计数排序
原理:找出数组a中最大的值n,生成一个新的长度为n的数组b,旧数组a的元素作为新数组b的下标,往里面填元素个数;
优点:性能比冒泡、插入、选择都快;
缺点:空间占用大,需要生成一个新的数组,且长度可能无限大;
public int[] countSort(int[] arr){
int max = Integer.MIN_VALUE;// 最小
int min = Integer.MAX_VALUE;
//找出数组中的最大最小值
for(int i = 0; i < arr.length; i++){
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
int help[] = new int[max];
//找出每个数字出现的次数
for(int i = 0; i < arr.length; i++){
// 做偏移
int mapPos = arr[i] - min;
help[mapPos]++;
}
//还原数据
int index = 0;
for(int i = 0; i < help.length; i++){
while(help[i]-- > 0){
arr[index++] = i+min;
}
}
return arr;
}
归并排序
和希尔排序相反,分组从2开始,2、4、8..;
// 归并排序
public void mergeSort(int[] nums) {
int[] tmpArray = new int[nums.length];
mSort(nums, tmpArray, 0, nums.length - 1);
}
public void mSort(int[] nums, int[] tmps, int left, int right) {
int center;
if (left < right) {
center = (left + right) / 2;
mSort(nums, tmps, left, center);
mSort(nums, tmps, center + 1, right);
merge(nums, tmps, left, center + 1, right);
}
}
// 空间归并
public void merge(int[] nums, int[] tmps, int lpos, int rpos, int rightEnd) {
int i, leftEnd, numElements, tmpPos;
leftEnd = rpos - 1;
tmpPos = lpos;
numElements = rightEnd - lpos + 1;
while (lpos <= leftEnd && rpos <= rightEnd) {
if (nums[lpos] <= nums[rpos])
tmps[tmpPos++] = nums[lpos++];
else
tmps[tmpPos++] = nums[rpos++];
}
while (lpos <= leftEnd)
tmps[tmpPos++] = nums[lpos++];
while (rpos <= rightEnd)
tmps[tmpPos++] = nums[rpos++];
for (i = 0; i < numElements; i++, rightEnd--)
nums[rightEnd] = tmps[rightEnd];
}