1.冒泡排序,这个应该是大家都熟悉的。(都是从小到大排)
原理:简单理解就是依次把最小的数往上冒。
public void bubbleSort(int[] data) {
//较小的数往前冒,每一次外层循环,保证第i个数是第i大的
for(int i=0;i<data.length;i++){
for(int j=i+1;j<data.length;j++){
//假如后面有比data[i]小的,就交换过来
if(data[i]>data[j])
swap(data, i, j);
}
}
?其中的swap方法表示交换数组中两个位置的数据,代码如下:
private void swap(int[] data, int x, int y) {
int temp = data[x];
data[x] = data[y];
data[y] = temp;
}
?
2.选择排序
个人感觉可以看作是冒泡排序方法的改进版。冒泡排序是只要后面的比当前的小就交换,而选择排序是从后面没排好的找到最小值的位置,最后只需要交换一次。
public void selectSort(int[] data) {
int index;//当前最小值的位置
for(int i=0;i<data.length;i++){
index=i;
for(int j=i+1;j<data.length;j++){
if(data[index]>data[j]){
index=j;//记录最小位置
}
}
swap(data, i, index);//把当前最小值保存到第i个位置
}
}
?3.插进排序
这种方法的思路是,将一个记录插进到已排好序的有序表(有可能是空表)中,从而得到一个新的记录数增1的有序表。也就是说程序开始把第一个数当作一个有序表,然后依次加进后面的n-1个数,每加进一个数,都要保证得到的序列是排好序的。
public void insertSort(int[] data) {
for (int i = 1; i < data.length; i++) {
// 把第i个位置的数插到前i-1个数的某个位置,保证前i个数排好序
int temp = data[i];// 首先保存第i个数的值
int j;
for (j = i; j > 0; j--) {
if (data[j - 1] > temp)// 假如前面的数比第i个位置的数大,说明得往后移
data[j] = data[j - 1];
else
break;
}
data[j] = temp;// 找到合适位置后,插进即可
}
}
?4.快速排序
??? 从数组中随意找出一个数(这里取数组的第一个数),将大于和小于它的数分置于其两边,然后再将其两边的数组都以同样的方法执行 .主要分三步:1) 从数列中挑出一个元素,称为 “基准”(pivot) 2)重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分割之后,这个称为分割(partition)操纵。3)递回地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
private void quickSort(int data[], int low, int high) {
int i, j, pivot;
i = low;
j = high;
if (low < high) {// 通过这个条件结束循环
// 第一步,选择基准,这里就选择第一个数
pivot = data[i];
//第二步,通过下面这个循环,把数组中小于基准的放到数组左边,大于基准的放到数组右边
while (i < j) {
// 1.从右往左找到第一个小于pivot的元素
while (i < j && data[j] > pivot)
j--;
if (i < j) {
data[i] = data[j];// 第i个元素保存右边第一个小于pivot的
i++;
}
//2.从左往右找,找到第一个大于pivot的元素
while (i < j && data[i] < pivot)
i++;
if (i < j) {
data[j] = data[i];// 第j个元素保存左边第一个大于pivot的
j--;
}
}
data[i] = pivot;//第i个位置就是基准的位置
//第三步,递回调用该算法,把基准左边,右边的分别排序
quickSort(data, low, i - 1);
quickSort(data, i + 1, high);
}
}
?5.希尔排序(shell)缩小增量排序
????? Shell排序法是对相邻指定间隔(称为间隔)的元素进行比较,直到使用当前间隔进行比较的元素都按顺序排序为止.Shell把间隔缩小一半,然后继续处理,当间隔终极变为1,并且不再出现变化时,Shell排序也就完成了其处理过程.实际上就是根据增量把数组分成几部分,每部分进行插进排序即可。个人理解对每个部分的排序可以采取任何的简单排序方法。
public void shellSort(int[] data) {
//这里把增量初始化为数组长度的一半,然后依次减半,当然也可以传进一个增量数组
for (int inc = data.length / 2; inc > 2; inc /= 2) {
for (int j = 0; j < inc; j++) {
shellInsertSort(data, j, inc);//每一组内进行插进排序
}
}
shellInsertSort(data, 0, 1);//最后进行一次所有元素的排序
}
//这个算法实在就是一次插进排序,只不过有个增量inc
private void shellInsertSort(int[] data, int start, int inc) {
int temp;
for (int i = start+inc; i < data.length; i+=inc) {
// 把第i个位置的数插到前i-1个数的某个位置,保证前i个数排好序
temp = data[i];// 首先保存第i个数的值
int j;
for (j = i; j >=inc; j-=inc) {
if (data[j - inc] > temp)// 假如前面的数比第i个位置的数大,说明得往后移
data[j] = data[j - inc];
else
break;
}
data[j] = temp;// 找到合适位置后,插进即可
}
}
?
从代码中可以看出,组内的排序方法和前面讲过的插进排序完全一样。?
6.回并排序
算法思想是每次把待排序列分成两部分,分别对这两部分递回地用回并排序,完成后把这两个子部分合并成一个
序列。
回并排序借助一个全局性临时数组来方便对子序列的回并,该算法核心在于回并。
/**
* @param data 是需要排序的原数组
* @param temp 是个临时数组,数组大小和data一样
* @param left 左边界
* @param right 右边界
*/
private void mergeSort(int[] data, int[] temp, int left, int right) {
if (left >= right)//就剩一个元素时,直接返回,直接合并就行了。
return;
int mid = (left + right) / 2;//获得数组的中间位置
mergeSort(data, temp, left, mid);//对左半部分递回调用排序算法
mergeSort(data, temp, mid + 1, right);//对右半部分分递回
//这一步是把原数组中的值保存到临时数组中
for (int i = left; i <= right; i++) {
temp[i] = data[i];
}
//下面是完成合并,也就是把左右两个有序的数组合并到一个数组中,并使之有序
int l= left;
int r = mid + 1;
for (int cur = left; cur <= right; cur++) {
if (l == mid + 1)//假如第一个数组已经全部比较完了,那么我们只要直接复制第二个数组的条目到合并数组中即可
data[cur] = temp[r++];
else if (r > right)//假如第二个数组已经全部比较完了,那么我们只要直接复制第一个数组的条目到合并数组中即可
data[cur] = temp[l++];
else if (temp[l] < temp[r])//把比较的两个条目中关键值小的放到合并数组中
data[cur] = temp[l++];
else
data[cur] = temp[r++];
}
}
7、堆排序?