用java实现冒泡,插入,选择等排序
冒泡排序(优化)
1.思想
从零号下标开始遍历,相邻的两个数相互比较,将最大的数沉底。
2.代码
public void bubble(int[] a){
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length-1-i; j++) {
if(a[j]>a[j+1]) swap(a,j,j+1);//把第j和第j+1下标的值交换
}
}
}
优化
public void bubble(int[] a){
for (int i = 0; i < a.length - 1; i++) {
boolean s=false;//设置标记
for (int j = 0; j < a.length-1-i; j++) {
if(a[j]>a[j+1]){
swap(a,j,j+1);
s=true;
}
}
if(!s)break;
}
}
选择排序
1.思想
假设零号位为最小值,然后拿零号位与后面的数依次比较,如果大于则交换。将数组遍历一遍以后,第一个值即为最小值。然后再将一号位设为最小值与后面比较。
2.代码
public void select(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = i + 1; j < a.length; j++) {
if (a[i] > a[j]) swap(a, i, j);
}
}
}
插入排序
1.思想
以零号位开始为一个有序数组,依次加入数组下一位数,加入的这位数从前往后与前面的数比较,使它成为有序数组。如a[0]本身有序;加入下一位啊a[1],对a[0:1]进行排序,假如a[1]< a[0]则交换,交换后a[0:1]有序;加入下一位a[2],将a[0:2]有序,依次加入到数组最后一位,排序后数组有序。
2.代码
public void insert(int[] a) {
for (int i = 1; i < a.length; i++) {
for (int j = i - 1; j >= 0; j--) {
if (a[j + 1] < a[j]) swap(a, j + 1, j);
}
}
}
快速排序(递归)
1.思想
任取待排序对象中的某个对象作为基准,按照该对象的关键码大小,将整个对象序列划分为左右两个子序列。其中,左侧子序列中所有的关键码都小于或等于基准对象的关键码;右侧子序列中所有对象的关键码都大于基准对象的关键码。此时基准对象所在的位置也就是该对象在该序列中最终应该安放的位置。然后递归的在左右子序列中重复实施上述的方法,直至所有的对象都放到相应的位置上为止。
2.代码
public int portion(int[] a, int left, int right) {
int tmp = a[left];
while (left < right) {
while (left < right && a[right] >= tmp) --right;
a[left] = a[right];
while (left < right && a[left] <= tmp) ++left;
a[right] = a[left];
}
a[left] = tmp;
return left;
}
public void quickSort(int[] a, int start, int end) {
int par = portion(a, start, end);
if (par > start + 1) quickSort(a, start, par - 1);
if (par < end - 1) quickSort(a, par + 1, end);
}
快速排序(非递归)
1.思想
递归的快排算法是编译器自动用栈来实现的,当递归层次比较深的时候,需要占用比较大的进程栈空间,会造成进程栈溢出的危险。因此我们可以自己用栈模拟递归过程,即每次从栈顶取出一部分做划分之后,都把新的两部分的起始位置分别入栈。
2.代码
public static int partion(int[] a, int low,int high) {
int tmp = a[low];
while(low < high) {
while(low < high && a[high] >= tmp ) {
--high;
}
if(low >= high) {
break;
}else {
a[low] = a[high];
}
while(low < high && a[low] <=tmp) {
++low;
}
if(low >= high) {
break;
}else {
a[high] = a[low];
}
}
a[low] =tmp;
return low;
}
public static void QSort(int[] a) {
int[] stack = new int[a.length];
int top = 0;
int low =0;
int high = a.length-1;
int par =partion(a, low, high);
if(par > low + 1) {
stack[top++] = low;
stack[top++] = par - 1;
}
if(par < high - 1) {
stack[top++] = par + 1;
stack[top++] = high;
}
//出栈
while(top > 0) {
high = stack[--top];//最后一次入栈top++了,所以这里用--top而不是top--
low = stack[--top];
par = partion(a,low,high);
if(par > low+1) {
stack[top++] = low;
stack[top++] = par - 1;
}
if(par < high-1) {
stack[top++] = par+1;
stack[top++] = high;
}
}
}
shell排序(放大版的插入排序)
1.思想
(shell()方法的思想)先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的的记录放在同一个组中。先在各组内进行直接插入排序;
(shellSort()的思想)然后,取第二个增量d2< d1重复上述的分组和排序,直至所取的增量dt=1(dt< dt-l< …< d2< d1),即所有记录放在同一组中进行直接插入排序为止。
2.代码
public void shell(int[] a, int gap) {
for (int i = gap; i < a.length; i++) {
for (int j = i - gap; j >= 0; j = j - gap) {
if (a[j + gap] < a[j]) swap(a, j + gap, j);
}
}
}
public void shellSort(int[] a) {
int[] d = {7, 3, 1};
for (int i = 0; i < d.length; i++) {
shell(a, d[i]);
}
}
堆排序
1.思想
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了
2.代码
//获取最后一个左孩子的父节点
private int lastLeftChildrenParent(int size){
return size/2-1;
}
//获取当前节点的左孩子
private int leftChildren(int i){
return i * 2 + 1;
}
public void adjust(int[] a, int start, int end) {
int tmp = a[start];
for (int i = leftChildren(start); i <= end; i = leftChildren(i) ) {
if (i < end && a[i] < a[i + 1]) i++;
if (a[i] > tmp) {
a[start] = a[i];
start = i;
} else break;
}
a[start] = tmp;
}
public void heapSort(int[] a) {
//1.将数组构造成大根堆
for (int i = lastLeftChildrenParent(a.length); i >= 0; i--) {
adjust(a, i, a.length - 1);
}
//2.利用堆排序
for (int i = 0; i < a.length - 1; i++) {
swap(a, 0, a.length - 1 - i);
adjust(a, 0, a.length - 2 - i);
}
}
-----------.
归并排序
1.思想
基本思路就是将数组分成按a.length/2n个组2n个数,如下面左边第三行是第二次分组,分了5个组,每组21个数。然后建立一个临时数组,将相邻的两个组合并成一个有序的组,放入临时数组里。直到2n>=a.length。
2.代码
public static void mergeSort(int[] a) {
for (int i = 1; i < a.length; i = i * 2) {
merge(a, i);
}
}
public static void merge(int[] a, int gap) {
int start1 = 0;//第一组开头
int end1 = start1 + gap - 1;//第一组结尾
int start2 = end1 + 1;//第二组开头
int end2 = start2 + gap - 1 < a.length - 1 ? start2 + gap - 1 : a.length - 1;//第二组结尾
int[] tmpa = new int[a.length];//用来合并的临时数组
int i = 0;
while (start2 < a.length) {//将相邻为gap的组,利用临时数组,两两合并
while (start1 <= end1 && start2 <= end2) {
if (a[start1] < a[start2]) tmpa[i++] = a[start1++];
else tmpa[i++] = a[start2++];
}
while (start1 <= end1) tmpa[i++] = a[start1++];//如果第二组先遍历完,将第一组补到临时数组后面
while (start2 <= end2) tmpa[i++] = a[start2++];//如果第一组先遍历完,将第二组补到临时数组后面
start1 = end2 + 1;
end1 = start1 + gap - 1;
start2 = end1 + 1;
end2 = start2 + gap - 1 < a.length - 1 ? start2 + gap - 1 : a.length - 1;//如果最后一次只有第一组,不够第二组,退出循环
}
while (i < a.length) tmpa[i++] = a[start1++];//将最后一次第一组补上
for(int j = 0;j<a.length;j++) a[j] = tmpa[j];//将临时数组复制到原数组
}