一、插入排序(稳定的)
代码:
//插入排序(稳定的)
/*
* 其实现思路是:序列前几个元素已经有序后,将后面的元素遍历插入到前面的序列中
* 时间复杂度是:O(n2)
* */
public static void insertSort(int a[]) {
for(int i = 2 ; i <= a.length - 1 ; i ++) { //第一个元素不用插入 , 所以操作元素是2 ~ n
if(a[i] < a[i - 1]) {
a[0] = a[i];
int j;
for(j = i - 1 ; a[0] < a[j] ; j --) a[j + 1] = a[j]; //后移操作
a[j + 1] = a[0]; //j+1 是因为前一个循环后j在插入位置的前面一个位置
}
}
}
折半插入排序
代码:
public static void binary_insertSort(int a[]) {
for(int i = 2 ; i < a.length ; i ++) {
if(a[i] < a[i - 1]) {
a[0] = a[i];
int low = 1;
int high = i - 1;
while(low <= high) {
int mid = (low + high) / 2;
if(a[0] > a[mid]) low = mid + 1;
else high = mid - 1;
}
int j;
for(j = i - 1; j >= high + 1; j --) {
a[j + 1] = a[j];
}
a[j + 1] = a[0];
}
}
}
问题:①为什么最后j选取和high+1进行比较?
这是由二分所决定的,在二分结束时high指向最大的小于a[0]的元素,low指向最小的大于a[0]的元素,且low = high + 1;所以对于插入位置需要将从 high + 1 ~ i - 1的元素进行后移。
二、希尔排序(不稳定的)
希尔排序是在插入排序的基础上实现的。
代码:
public static void shell(int a[]) {
int n = a.length;
for(int gap = n / 2 ; gap > 0 ; gap /= 2) { //确定步长因子序列,每次都是减半
for(int i = gap ; i < n ; i ++) {
int temp = a[i];
int j;
for(j = i ; j >= gap && a[j - gap] > temp ; j -= gap) { //对每一个步长组进行插入排序
a[j] = a[j - gap];
}
a[j] = temp;
}
}
}
解释:首先通过一个for循环来生成步长因子序列,然后对于每一个步长因子,对于确定出来的分组进行插入排序。
对比希尔排序中插入排序和普通插入排序的区别:
①普通插入排序中最后插入元素需要索引+1,因为循环的最后j更新的位置是插入位置的前一个位置,而希尔排序中由于更新后j就是指的是插入位置。
三、冒泡排序(稳定的)
代码:
public static void bubble_sort(int a[]){
for(int i = 1 ; i <= a.length - 1 ; i ++) { //此处a.length = n + 1
int flag = 0;
for(int j = 1 ; j <= a.length - 1 - i ; j ++) {
if(a[j] > a[j + 1]) {
a[0] = a[j];
a[j] = a[j + 1];
a[j + 1] = a[0];
flag = 1;
}
}
if(flag == 0) break; //当整个过程中没有交换操作则是有序的
}
}
四、快速排序(不稳定的)
代码:
public static void quick_sort(int a[] , int l , int r) {
if(l >= r) return;
int x = a[(l + r) / 2] , i = l - 1 , j = r + 1;
while(i < j) {
do i ++; while(a[i] < x);
do j -- ; while(a[j] > x);
if(i < j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
quick_sort(a , l , j);
quick_sort(a , j + 1, r);
}
五、归并排序
代码:
public static void merge_sort(int a[] , int l , int r , int temp[]) {
if(l >= r) return;
int mid = (l + r) / 2 , i = l , j = mid + 1 , k = 0;
merge_sort(a , l , mid , temp);
merge_sort(a , mid + 1 , r , temp);
while(i <= mid && j <= r) {
if(a[i] < a[j]) temp[k ++] = a[i ++];
else temp[k ++] = a[j ++];
}
while(i <= mid) temp[k ++] = a[i ++];
while(j <= r) temp[k ++] = a[j ++];
for(i = l , j = 0 ; i <= r ; i ++ , j ++) a[i] = temp[j];
}
·六、选择排序
代码:
public static void select_sort(int a[]) {
for(int i = 1 ; i < a.length - 1 ; i ++) { //只用循环n - 1次因为最后第n次已经是有序的
int k = i;
for(int j = i + 1 ; j <= a.length - 1; j ++) {
if(a[j] < a[k]) k = j; //找到目前最小的位置
}
if(i != k) {
a[0] = a[i];
a[i] = a[k];
a[k] = a[0];
}
}
}
七、堆排序
代码:
//堆排序
public static void heapsort(int a[]) {
//先建堆(从顶到底建堆)
for(int i = 0 ; i < a.length ; i ++) {
heapInsert(a , i);
}
//进行堆排序:由于是大顶堆,所以每次将堆顶与最后结点交换,然后将堆顶下沉
int size = a.length;
while(size > 1) {
swap(a , 0 , --size);
heapify(a , 0 , size);
}
}
//堆排序的优化
public static void heapsort2(int a[]) {
int size = a.length;
for(int i = a.length - 1 ; i >= 0 ; i --) {
heapify(a , i , size);
}
while(size > 1) {
swap(a , 0 , --size);
heapify(a , 0 , size);
}
}
//堆上调函数
public static void heapInsert(int a[] , int i) {
//对于堆的一个结点i其父节点是(i - 1)/ 2 , 当索引从0开始时。
while(a[i] > a[(i - 1) / 2]) {
swap(a , i , (i - 1) / 2);
i = (i - 1) / 2;//更新位置,确保能够找到最终的位置
}
}
//堆下调函数
public static void heapify(int a[] , int i , int size) {
int l = 2 * i + 1; //先找到左节点
while(l < size) { //边界是size
int best = l + 1 < size && a[l + 1] > a[l] ? l + 1 : l; //找到两个结点中最大的一个
best = a[best] > a[i] ? best : i; //比较子节点和当前结点哪一个更大并更新
if(best == i) {
break;
}
swap(a , best , i); //当子节点更大时调整位置
i = best; //更新位置
l = 2 * i + 1;
}
}
//堆排序中交换函数
public static void swap(int a[] , int i , int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
八、主方法测试输出
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int a[] = new int[n + 1];
System.out.println("(输入序列):");
for(int i = 1 ; i <= n ; i ++) {
a[i] = scan.nextInt();
}
//插入排序
int temp[] = a.clone();
System.out.println("插入排序的结果:");
insertSort(temp);
for(int i = 1 ; i <= n ; i ++) {
System.out.print(temp[i] + " ");
}
System.out.println();
//插入排序优化折半插入排序
int temp1[] = a.clone();
System.out.println("折半插入排序的结果:");
binary_insertSort(temp1);
for(int i = 1 ; i <= n ; i ++) {
System.out.print(temp1[i] + " ");
}
System.out.println();
//希尔排序
int temp2[] = a.clone();
System.out.println("希尔排序的结果:");
shell(temp2);
for(int i = 1 ; i <= n ; i ++) {
System.out.print(temp2[i] + " ");
}
System.out.println();
//快速排序
int temp3[] = a.clone();
System.out.println("快速排序的结果:");
quick_sort(temp3 , 1 , n);
for(int i = 1 ; i <= n ; i ++) {
System.out.print(temp3[i] + " ");
}
System.out.println();
//归并排序
int temp4[] = a.clone();
System.out.println("归并排序的结果:");
int tmp[] = new int[n + 1];
merge_sort(temp4 , 1 , n , tmp);
for(int i = 1 ; i <= n ; i ++) {
System.out.print(temp4[i] + " ");
}
System.out.println();
//冒泡排序
int temp5[] = a.clone();
System.out.println("冒泡排序的结果:");
bubble_sort(temp5);
for(int i = 1 ; i <= n ; i ++) {
System.out.print(temp5[i] + " ");
}
System.out.println();
//选择排序
int temp6[] = a.clone();
System.out.println("选择排序的结果:");
select_sort(temp6);
for(int i = 1 ; i <= n ; i ++) {
System.out.print(temp6[i] + " ");
}
System.out.println();
//堆排序(为处理索引问题,这里重新进行一下输入操作)
System.out.println("新输入一个序列用于堆排序:");
int b[] = new int[n];
for(int i = 0 ; i < n ; i ++) {
b[i] = scan.nextInt();
}
System.out.println("堆排序的结果:");
heapsort2(b);
for(int i = 0 ; i < n ; i ++) {
System.out.print(b[i] + " ");
}
System.out.println();
}

被折叠的 条评论
为什么被折叠?



