一、冒泡排序:
1、通过比较相邻两个元素,把大的元素放在索引大的位置上,这样比较n-1-i次后,就将最大的元素冒泡到最后面
2、这样的过程要找n-1次
时间复杂度:
最好情况已经排好序O(n)
最差情况反序O(n^2)
private static void bubbling(int[] a,int n){
int temp;
for(int i = 0; i < n-1; i++){
for(int j = 0; j < n-1-i; j++){
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
}
冒泡排序改进1:
考虑到过程1存在不需要交换的数据,不需要交换的数据在过程2也不需要交换
记录最后一次交换的位置,下一次循环到这个位置就可以了
private static void bubbling1(int[] a,int n){
int temp;
int posEnd = n-1;//一次循环中最后一次交换的位置
int pos;
while(posEnd>0){
//当不需要交换的时候,自然也就排序完成
pos=0;
for(int j = 0; j < posEnd; j++){
if(a[j]>a[j+1]){
pos = j;
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
posEnd = pos;
}
}
冒泡排序改进2:
考虑到每次循环只找到最大的值或者最小的值,可以每次找到最小和最大的值吗?
private static void bubbling2(int[] a,int n){
int temp,j;
int low = 0;
int high = n-1;
while(low<high){
for(j=low;j<high;j++){
if(a[j]>a[j+1]){
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
high--;
for(j=high;j>low;j--){
if(a[j]<a[j-1]){
temp=a[j];
a[j]=a[j-1];
a[j-1]=temp;
}
}
low++;
}
}
二、快速排序:
分治法的思想
1、取一个基数(这里取第一个元素)
2、让小于这个基数的数放在基数的左边,大于这个基数的数放在这个基数的右边
3、递归过程1、2
重要的是过程2,从数组的两端遍历,依次和基数进行判断,右端如果大于基数(右端一定要先判断,这样最后两端要相遇的时候,
保证了在数值小的地方相遇,然后相遇的地方与基数互换,当然,如果基数选择的是最后一个元素,那么就要从左端开始判断),
那么++,左端如果小于基数,那么–,当找到了右端的小于基数的值和左端的大于基数的值,如果左右两端没有遇到,交换这两
个值,然后再判断左右两端是否遇到,如果没遇到,那么继续这个过程,直到左右两端遇到。
例如:3,9,5,2,6,1;1与9交换3,1,5,2,6,9;2与5交换3,1,2,5,6,9;这时high==low,2与3交换2,1,3,5,6,9,
这样2,1在3的左边,而5,6,9在3的右边。
时间复杂度:
最好的情况是每次把上一次的数组平均分成两个子数组。设数组总数一共为n,如果把这n个数每次分成2半最后每个数组只
包含一个元素,假设要分k次,则2的k次方=n,解得k=log2n(log以2为底对n取对数).也就是说要分log2n次,而每次都
是处理n个数据。所以总的时间复杂度为O(nlog2n)。
private static void quickSort(int[] a,int left,int right){
if(left<right){
int key = a[left];
int low = left;
int high=right;
int temp;
while(low!=high){
while(low<high && a[high]>=key){
high--;
}
while(low<high && a[low]<=key){
low++;
}
if(low<high){
temp = a[low];
a[low]= a[high];
a[high]=temp;
}
}
a[left]=a[low];
a[low]=key;
quickSort(a,left,low-1);
quickSort(a,low+1,right);
}
}
三、插入排序:
从数组第二个元素开始(第一个元素已经排好序)当作插入值key,先判断key是否比它左边的哥们大,如果比它左边的哥们大,那么不需要插入,就在原位置就行了,
将key与排好序的从右到左依次作比较,如果key一直是小数,那么就将比较值往右移位,直到找到一个小于等于key或者找到最后一个,就在这个位置上将key插入。
时间复杂度:
最好的情况下数组已经排好序,线性复杂度O(n)
最差的情况下逆序O(n^2)
private static void insertSort(int[] a,int n){
int key;
int j;
for(int i=1;i<n;i++){
if(a[i]<a[i-1]){
j=i;
key = a[i];
while(j>0 && key<a[j-1]){
a[j]=a[j-1];
j--;
}
a[j]=key;
}
}
}
四、选择排序:
每次从待排序的数组中找到最小值,然后放在固定的位置
首先设置第一个元素是最小值,然后遍历后面的元素与之比较,找出最小值min,记录最小值的索引index(用于存放被最小值替换下来的值)
时间复杂度:
O(n^2)
private static void selectSort(int[] a,int n){
int min;
int index;
int temp;
for(int i = 0;i<n;i++){
min = a[i];
index = i;
for(int j=i+1;j<n;j++){
if(a[j]<min){
min=a[j];
index=j;
}
}
temp = a[i];
a[i] = min;
a[index] = temp;
}
}
五、堆排序:
1、建堆
2、将堆顶的元素和最后一个元素替换,替换完,剩下的元素需要再次调整为堆
3、重复过程2,,直到替换了n-1次,完成排序
private static void heapSort(int[] a,int n){
int temp;
buildHeap(a,n);
for(int i=n-1;i>0;i--){
//堆顶和最后一个节点交换
temp = a[i];
a[i] = a[0];
a[0] = temp;
//交换之后再把没排序的堆进行调整
// buildHeap(a,i);
adjustHeap(a,i,0);
}
}
初始化堆
从最后一个父节点开始,到堆顶,从下到上调整堆。
private static void buildHeap(int[] a, int n) {
for(int i = n/2;i>=0;i--){
adjustHeap(a,n,i);
}
}
调整堆:
@parama数组,n数组的长度,i要调整的父节点
假设父节点是最大值,如果子节点不超出n(也就是子节点存在),那么将子节点与父节点比较,将最大值设为父节点,
如果最大值是在子节点中,那么将子节点的值与父节点的值替换后,被替换的子节点可能就不再是堆,需要调整以子节点为父节点成为堆。
直到子节点是叶子节点为止
private static void adjustHeap(int[] a, int n, int i) {
int lchild = 2*i+1;//左子节点
int rchild = 2*i+2;//右子节点
int max = i;
int temp;
if(i<n/2){
if(lchild<n && a[max]<a[lchild]){
max = lchild;
}
if(rchild<n && a[max]<a[rchild]){
max = rchild;
}
if(i!=max){
//将最大值放在父节点
temp = a[max];
a[max] = a[i];
a[i] = temp;
adjustHeap(a,n,max);
}
}
}
六、归并排序
/**
* 归并排序:
* 将数组用递归进行二分分开,直到高位和低位相邻的时候,分开结束,进行归并排序
* @param a 待排序的数组
* @param low 低位
* @param high 高位
*/
private static void mergeSort(int[] a, int low, int high){
if(low<high){
int mid = (low+high)/2;
mergeSort(a,low,mid);
mergeSort(a,mid+1,high);
merge(a,low,mid,high);
}
}
/**
* 将数组a[low,mid]和a[mid+1,high]归并排序到一个新数组,这个过程是这样的:
* 1、取a[low]和a[mid+1]进行比较,然后将小者放进新数组,新数组位置+1,low+1,
* 大者也放进新数组中,新数组位置+1,mid+1+1,这个过程直到两个数组有一个到达尽头
* 2、将两个数组剩下的部分也放进新数组中
* 3、这样这个新数据就是两个待排序的数据的归并排序数组,将这个新数组复制到最终要排序的数组a中,排序结束。
* @param a 带排序
* @param low 低位
* @param mid 中位
* @param high 高位
*/
private static void merge(int[] a, int low, int mid, int high) {
int i = low;
int j = mid+1;
int k = 0;
int[] b = new int[high-low+1];
while(i<=mid && j<=high){
if(a[i]<a[j]){
b[k++]=a[i++];
}else{
b[k++]=a[j++];
}
}
while(i<=mid){
b[k++]=a[i++];
}
while(j<=high){
b[k++]=a[j++];
}
for(i=0;i<k;i++){
a[low+i] = b[i];
}
}