1、冒泡排序
从前往后让相邻位置的两个数字比较,这样可以把最大的或最小的放到末尾位置,如果最大的数字是在第一个位置,那么这个数字每次比较都会往后移动一位,直到末尾位置,其他数字同理。
public void bubbleSort(int a[]) {
int i, j, t;
for (i = 0; i < a.length - 1; i++) {
for (j = 0; j < a.length - 1 - i; j++) {
//前面的元素比后面大时交换位置,把最大的放后面
if (a[j] > a[j + 1]) {
t = a[j + 1];
a[j + 1] = a[j];
a[j] = t;
}
}
}
}
2、简单选择排序
让第一个和后面所有的数字比较,这样可以先找出最小的数字放在第一个位置,然后依次找出。
public void simpleSelectSort(int a[]) {
int i, j, t;
for (i = 0; i < a.length - 1; i++) {
for (j = i + 1; j < a.length; j++) {
if (a[i] > a[j]) {
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
}
3、直接插入排序
以从小到大排序为例: 从第二个数字(n1)开始,从后往前和所有的数字(很明显当轮到n1时它前面的数字一定是有序的)比较,直到找到一个不大于n1的数字(n2)为止, 然后把n1插到n2的后面。
public void insertSort(int[] a) {//
int i, j, k;
for (i = 1; i < a.length; i++) {
int t = a[i];
for (j = i - 1; j >= 0; j -= 1) {
if (t < a[j]) {
a[j + 1] = a[j];
} else {
break;
}
}
j += 1;// 循环结束有两种情况,
// 1、正常结束,a[i]最小此时j=-1,t应该在a[0]的位置,所以需要j+1
// 2、a[j]不小于啊a[i],此时t应该插入a[j+1]的位置,所有需要j+1
a[j] = t;
}
}
4、希尔排序
分组进行直接插入排序。不过不是按前后位置分为n组,而是每隔n个位置的数分为一组,n一直减小,直到为1,这个时候相隔1个位置的数为一组,也就是说整个数组为一组 再进行一次插入排序。
public void insertSort(int[] a, int q) {
int i, j, k;
for (i = q; i < a.length; i++) {
int t = a[i];
for (j = i - q; j >= 0; j -= q) {
if (t < a[j]) {
a[j + q] = a[j];
} else {
break;
}
}
j += q;// 循环结束有两种情况,
// 1、正常结束,a[i]最小此时j=-1,t应该在a[0]的位置,所以需要j+1
// 2、a[j]不小于啊a[i],此时t应该插入a[j+1]的位置,所有需要j+1
a[j] = t;
}
}
public void shellSort(int[] a) {
int i;
for (i = a.length / 2; i >= 1; i--) {
insertSort(a, i);
}
}
5、堆排序
算法的关键就是构造大顶堆(小顶堆) 构造过程充分的利用了完全二叉树的各种性质。
public void heapSort(int[] a) {
int l = a.length - 1;//下标为0的位置没有用,所有长度需要-1
/*
* 为什么i从l/2开始? 对完全二叉树进行编号,假设一个节点的编号是i,那么它的左右子
*节点的编号一定是2i和2i+1(当然它也可能没有子节点)。
* 如果最后一个元素的编号是l,那么它的父节点的编号一定是l/2(取整) 在下面的循环中
*i是递减的,既然i是最后一个节点的父节点,
* 那么随着i的减少,它会包含所有节点的父节点
*/
for (int i = l / 2; i > 0; i--) {
heapAdjust(a, i, l);// 先将输入的数组构造为最初的大顶堆
}
//printArray(a);
for (int i = l; i > 1; i--) {
swp(a, 1, i); // 将大顶堆的堆顶元素放到数组的最后面
// 重新构造新的大顶堆,因为数组最后的元素已经是上个大顶堆的堆顶
// 所有每次构造堆都可以去掉
heapAdjust(a, 1, i - 1);
//printArray(a);
}
}
private void swp(int[] a, int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
public void heapAdjust(int[] a, int s, int m) {
int temp = a[s];
/*
* s为一个父节点的编号,m是此时数组的长度 i=2*s,也就是所i是s的左子节点,
*i*=2,找到是下一层的左子节点
*/
for (int i = 2 * s; i <= m; i *= 2) {
/*
* 下面的两个判断语句,是从两个子节点中找出值大的那个 然后后面和父节点
*交换位置
*/
if (i < m && a[i] < a[i + 1]) {
i++;
}
if (temp >= a[i]) {
break;
}
/*
* 找到值大的子节点和父节点交换位置,然后更新s(空出a[i]的位置) 此时
* temp没有改变,仍然以它为基准,继续判断它将要去的位置的两个
* 子节点是否还有比它大的值,需要交换位置, 最后将temp存入空出的a[s]
*(s=i,a[i]位置)
*/
a[s] = a[i];
s = i;
}
a[s] = temp;
}
6、归并排序
将一组数据分为两组,然后再将两组数分为四组,一次类推,直到每组数组只有一个数字的时候开始合并,每次合并的时候比较大小 ,使得合并之后的数字是有序的,然后直到合并成完整的数组。
public void mergeSort(int[] a) {
MSort(a, 1, a.length-1);
}
public void MSort(int[] a, int left, int right) {
//条件成立时,代表每组数只有一个数字,可以开始合并了
if(left==right) {
return;
}
int center = (left + right) / 2;
MSort(a,left,center);
MSort(a,center+1,right);
merge(a,left,center,right);
//printArray(a);
}
public void merge(int[] a,int left,int center,int right) {
//System.out.println("merge "+left+" "+center+" "+right);
int i,j,k;
int[] b = new int[a.length];
/*
* 将两部分数组从头开始比较,小的存入新数组中,下标后移再次进行比较
* 合并的时候两个数组是基本有序的,所有从前往后比较就可以了
*/
for(i=k=left,j=center+1;i<=center&&j<=right;k++) {
if(a[i]<a[j]) {
b[k] =a[i];
i++;
} else {
b[k]=a[j];
j++;
}
}
//当循环结束的时候,两个数组一定有一个没有完全存入新的数组中
//这个时候需要将剩下的存入新的 数组中
for(;i<=center;i++) {
b[k++]=a[i];
}
for(;j<=right;j++) {
b[k++]=a[j];
}
for(i=left;i<=right;i++) {
a[i]=b[i];
}
}
7、快速排序
以最后一个元素或者第一个元素为基准,将大于基准的元素全部放到基准的后面,将小于基准的元素全部放到基准的前面,然后将基准前后两部分的元素分为两部分, 再找基准进行上面的操作,直到有序。
public void quickSort(int[] a, int left, int right) {
System.out.println(left+" "+right);
if (left < right) {
int middle = getMiddle(a, left, right);// 找出基准的位置
quickSort(a, left, middle - 1);
quickSort(a, middle + 1, right);
}
}
public int getMiddle(int[] a, int left, int right) {
int f = a[left];// 以每部分的第一个元素为基准,将a[left]位置空出
// System.out.println(f+" "+left+" "+right);
while (left < right) {
// 小于基准的元素都应该放到基准的前面
while (left < right && a[right] >= f) {
right--;
}
// 将小于f的数字放到前面的a[left]空出的位置,这样a[right]位置就空出了
a[left] = a[right];
// 大于基准的元素都应该放到基准的后面
while (left < right && a[left] <= f) {
left++;
}
// 将大于f的数字放到后面的a[right]空出的位置,这样a[left]位置空出了
// left,right是一直在变化的
a[right] = a[left];
}
a[left] = f;
return left;
}
完整代码:
package com.wpt;
import java.util.Arrays;
public class Sort {
/**
* 直接插入排序 以从小到大排序为例: 从第二个数字(n1)开始,从后往前和所有的数字(很明显当轮到n1时它前面的数字一定是有序的)比较,
* 直到找到一个不大于n1的数字(n2)为止, 然后把n1插到n2的后面。
*
* @param a
* @return
*/
public void insertSort(int[] a, int q) {
int i, j, k;
for (i = q; i < a.length; i++) {
//System.out.print("i=" + i + ",a[" + i + "]=" + a[i] + ": ");
int t = a[i];
for (j = i - q; j >= 0; j -= q) {
if (t < a[j]) {
a[j + q] = a[j];
} else {
break;
}
}
j += q;// 循环结束有两种情况,
// 1、正常结束,a[i]最小此时j=-1,t应该在a[0]的位置,所以需要j+1
// 2、a[j]不小于啊a[i],此时t应该插入a[j+1]的位置,所有需要j+1
a[j] = t;
/*
* int flag = 0; for (j = 0; j < i; j++) { if (a[i] < a[j]) { flag = 1; break; }
* } int t =a[i]; if (flag == 1) { for (k = i; k >j; k--) { a[k]=a[k-1]; } a[j]
* = t; }
*/
}
}
/**
* 希尔排序 分组进行直接插入排序。不过不是按前后位置分为n组,而是每隔n个位置的数分为一组
* n一直减小,直到为1,这个时候相隔1个位置的数为一组,也就是说整个数组为一组 再进行一次插入排序
*
* @param a
* @return
*/
public void shellSort(int[] a) {
int i;
for (i = a.length / 2; i >= 1; i--) {
insertSort(a, i);
//System.out.println();
}
}
/**
* 简单选择排序 让第一个和后面所有的数字比较,这样可以先找出最小的数字放在第一个位置,然后依次找出
*
* @param a
* @return
*/
public void simpleSelectSort(int a[]) {
int i, j, t;
for (i = 0; i < a.length - 1; i++) {
for (j = i + 1; j < a.length; j++) {
if (a[i] > a[j]) {
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
}
/**
* 冒泡排序 从前往后让相邻位置的两个数字比较,这样可以把最大的或最小的放到末尾位置,
* 如果最大的数字是在第一个位置,那么这个数字每次比较都会往后移动一位,直到末尾位置,其他数字同理
*
* @param a
* @return
*/
public void bubbleSort(int a[]) {
int i, j, t;
for (i = 0; i < a.length - 1; i++) {
for (j = 0; j < a.length - 1 - i; j++) {
if (a[j] > a[j + 1]) {
t = a[j + 1];
a[j + 1] = a[j];
a[j] = t;
}
}
}
}
/**
* 快速排序 以最后一个元素或者第一个元素为基准,将大于基准的元素全部放到基准的后面
* 将小于基准的元素全部放到基准的前面,然后将基准前后两部分的元素分为两部分,
* 再找基准进行上面的操作,直到有序
*
* @param a
* @param left
* @param right
*/
public void quickSort(int[] a, int left, int right) {
System.out.println(left+" "+right);
if (left < right) {
int middle = getMiddle(a, left, right);// 找出基准的位置
quickSort(a, left, middle - 1);
quickSort(a, middle + 1, right);
}
}
public int getMiddle(int[] a, int left, int right) {
int f = a[left];// 以每部分的第一个元素为基准,将a[left]位置空出
// System.out.println(f+" "+left+" "+right);
while (left < right) {
// 小于基准的元素都应该放到基准的前面
while (left < right && a[right] >= f) {
right--;
}
// 将小于f的数字放到前面的a[left]空出的位置,这样a[right]位置就空出了
a[left] = a[right];
// 大于基准的元素都应该放到基准的后面
while (left < right && a[left] <= f) {
left++;
}
// 将大于f的数字放到后面的a[right]空出的位置,这样a[left]位置空出了
// left,right是一直在变化的
a[right] = a[left];
}
a[left] = f;
return left;
}
/**
* 堆排序 算法的关键就是构造大顶堆(小顶堆) 构造过程充分的利用了完全二叉树的各种性质
*/
public void heapSort(int[] a) {
int l = a.length - 1;//下标为0的位置没有用,所有长度需要-1
/*
* 为什么i从l/2开始? 对完全二叉树进行编号,假设一个节点的编号是i,那么它的左右子 节点的编号一定是2i和2i+1(当然它也可能没有子节点)。
* 如果最后一个元素的编号是l,那么它的父节点的编号一定是l/2(取整) 在下面的循环中i是递减的,既然i是最后一个节点的父节点,
* 那么随着i的减少,它会包含所有节点的父节点
*/
for (int i = l / 2; i > 0; i--) {
heapAdjust(a, i, l);// 先将输入的数组构造为最初的大顶堆
}
//printArray(a);
for (int i = l; i > 1; i--) {
swp(a, 1, i); // 将大顶堆的堆顶元素放到数组的最后面
// 重新构造新的大顶堆,因为数组最后的元素已经是上个大顶堆的堆顶
// 所有每次构造堆都可以去掉
heapAdjust(a, 1, i - 1);
//printArray(a);
}
}
private void swp(int[] a, int i, int j) {
int t;
t = a[i];
a[i] = a[j];
a[j] = t;
}
public void heapAdjust(int[] a, int s, int m) {
int temp = a[s];
/*
* s为一个父节点的编号,m是此时数组的长度 i=2*s,也就是所i是s的左子节点, i*=2,找到是下一层的左子节点
*/
for (int i = 2 * s; i <= m; i *= 2) {
/*
* 下面的两个判断语句,是从两个子节点中找出值大的那个 然后后面和父节点交换位置
*/
if (i < m && a[i] < a[i + 1]) {
i++;
}
if (temp >= a[i]) {
break;
}
/*
* 找到值大的子节点和父节点交换位置,然后更新s(空出a[i]的位置) 此时temp没有改变,仍然以它为基准,继续判断它将要去的位置的两个
* 子节点是否还有比它大的值,需要交换位置, 最后将temp存入空出的a[s](s=i,a[i]位置)
*/
a[s] = a[i];
s = i;
}
a[s] = temp;
}
/**
* 归并排序
* 将一组数据分为两组,然后再将两组数分为四组,一次类推,
* 直到每组数组只有一个数字的时候开始合并,每次合并的时候比较大小
* 使得合并之后的数字是有序的,然后直到合并成完整的数组
* @param a
*/
public void mergeSort(int[] a) {
MSort(a, 1, a.length-1);
}
public void MSort(int[] a, int left, int right) {
//条件成立时,代表每组数只有一个数字,可以开始合并了
if(left==right) {
return;
}
int center = (left + right) / 2;
MSort(a,left,center);
MSort(a,center+1,right);
merge(a,left,center,right);
//printArray(a);
}
public void merge(int[] a,int left,int center,int right) {
//System.out.println("merge "+left+" "+center+" "+right);
int i,j,k;
int[] b = new int[a.length];
/*
* 将两部分数组从头开始比较,小的存入新数组中,下标后移再次进行比较
* 合并的时候两个数组是基本有序的,所有从前往后比较就可以了
*/
for(i=k=left,j=center+1;i<=center&&j<=right;k++) {
if(a[i]<a[j]) {
b[k] =a[i];
i++;
} else {
b[k]=a[j];
j++;
}
}
//当循环结束的时候,两个数组一定有一个没有完全存入新的数组中
//这个时候需要将剩下的存入新的 数组中
if(i<=center) {
for(;i<=center;i++) {
b[k++]=a[i];
}
}
if(j<=right) {
for(;j<=right;j++) {
b[k++]=a[j];
}
}
for(i=left;i<=right;i++) {
a[i]=b[i];
}
}
public void printArray(int[] a) {
for (int i : a) {
System.out.print(i + " ");
}
System.out.println();
}
public int[] initArray() {
int[] a = { 10, 300, 100, 2, 4, 6, 5, 32, 1, 43, 23, 8, 7, 6, 0 };
return a;
}
public static void main(String args[]) {
Sort sort = new Sort();
int[] a = sort.initArray();
int l = a.length;
System.out.println(a.length);
// 排序前
sort.printArray(a);
//插入排序
sort.insertSort(a,1);
System.out.println("插入排序:");
sort.printArray(a);
//希尔排序
a = sort.initArray();
sort.shellSort(a);
System.out.println("希尔排序:");
sort.printArray(a);
//简单选择排序
a = sort.initArray();
sort.simpleSelectSort(a);
System.out.println("简单选择排序:");
sort.printArray(a);
//冒泡排序
a = sort.initArray();
sort.bubbleSort(a);
System.out.println("冒泡排序:");
sort.printArray(a);
//快速排序
a = sort.initArray();
sort.quickSort(a,0,l-1);
System.out.println("快速排序:");
sort.printArray(a);
//堆排序,可以看到堆排序,归并排序是没有用到下标为0的元素的
a = sort.initArray();
sort.heapSort(a);
System.out.println("堆排序:");
sort.printArray(a);
//归并排序
a = sort.initArray();
sort.mergeSort(a);
System.out.println("归并排序:");
sort.printArray(a);
}
}
可能有错误,欢迎指出。