一, 插入排序
思想: 每步将一个待排序的记录,按其顺序码大小插入到前面已经排序的字序列的合适位置,直到全部插入排序完为止.
关键问题: 在前面已经排好序的序列中找到合适的插入位置.
两个常用方法:
–直接插入排序
–二分插入排序
1,直接插入排序(从后向前找到合适位置后插入),循环点记忆: for (int j = i-1; j >= left; j--)
public class ZcSort {
public static void main(String[] args) {
int[] a={49,38,65,97,76,13,27,49,78,34,12,64,1};
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
//直接插入排序
for (int i = 1; i < a.length; i++) {
//待插入元素
int temp = a[i];//每一次重新赋值temp
int j;
for (j = i-1; j>=0; j--) {
//将大于temp的往后移动一位
if(a[j]>temp){
a[j+1] = a[j];
}else{
break;
}
}
a[j+1] = temp;
}
System.out.println();
System.out.println("排序之后:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
}
}
文件初态不同时,直接插入排序所耗费的时间有很大差.若文件初态为正序,则每个待插入的记录只需要比较一次就能够找到合适的位置插入;
若初态为反序,则第a[i]个待插入记录需要比较i次才能找到合适位置插入;
2, 二分法插入排序(按二分法找到合适位置插入)
循环点记忆: for (j = i-1; j>=0; j--)
public class EfSort {
public static void main(String[] args) {
int[] a={49,38,65,97,176,213,227,49,78,34,12,164,11,18,1};
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
//二分插入排序
sort(a);
System.out.println();
System.out.println("排序之后:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
}
private static void sort(int[] a) {
for (int i = 0; i < a.length; i++) {
int temp = a[i];
int left = 0;
int right = i-1;
int mid = 0;
while(left<=right){
mid = (left+right)/2;
if(temp<a[mid]){
right = mid-1;
}else{
left = mid+1;
}
}
for (int j = i-1; j >= left; j--) {
a[j+1] = a[j];
}
if(left != i){
a[left] = temp;
}
}
}
}
二分插入排序的比较次数与待排序记录的初始状态无关,仅依赖于记录的个数;
当n较大时,比直接插入排序的最大比较次数少得多.但大于直接插入排序的最小比较次数,总体来说还是由于直接插入法.
二, 选择排序
思想: 每趟从待排序的记录序列中选择关键字最小的记录放置到已排序表的最前位置,直到全部排.
关键问题: 在剩余的待排序记录序列中找到最小关键码记录.
循环点记忆: (int j=i+1;j<a.length;j++)
public class XzSort {
public static void main(String[] args) {
int[] a={49,38,65,97,76,13,27,49,78,34,12,64,1,8};
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
//简单的选择排序
for (int i = 0; i < a.length; i++) {
int min = a[i];
int n=i; //最小数的索引
for(int j=i+1;j<a.length;j++){
if(a[j]<min){ //找出最小的数
min = a[j];
n = j;
}
}
a[n] = a[i];
a[i] = min;
}
System.out.println();
System.out.println("排序之后:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
}
}
三, 冒泡交换排序
基本思想(向右冒泡方式): 在要排序的一组数中,对当前还未排好序的范围内的全部数,自前到后对相邻的两个数依次进行比较和调整,让较大的数往右(往上)冒.
public class BubbleSort {
public static void main(String[] args) {
int[] a={49,38,65,97,76,13,27,49,78,34,12,64,1,8};
System.out.println("排序之前:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
//冒泡排序
for (int i = 0; i < a.length; i++) {
for(int j = 0; j<a.length-i-1; j++){
//这里-i主要是每遍历一次都把最大的i个数冒到最右边去了,没有必要再替换了
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
System.out.println();
System.out.println("排序之后:");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
}
}
冒泡排序是一种稳定的排序方法:
若文件初状为正序,则一趟起泡就可完成排序,排序码的比较次数为n-1,且没有记录移动,时间复杂度是(n);
若文件初态为逆序,则需要n-1趟起泡,每趟进行n-i次排序码的比较,且每次比较都移动三次,比较和移动次数均达到最大值:(n2).