排序算法
排序一:直接插入排序
每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。
1、第一趟比较前两个数,然后把第二个数按大小插入到有序表中;
2、第二趟把第三个数据与前两个数从前向后扫描,把第三个数按大小插入到有序表中;
3、依次进行下去,进行了(n-1)趟扫描以后就完成了整个排序过程。
直接插入排序属于稳定的排序,最坏时间复杂度为O(n^2),空间复杂度为O(1)。
下面按从小到大排序:
public class Sort { public static void main(String[] args) { int[] data = { 31, 23, 89, 10, 47, 68, 8, 22 }; insert_sort(data); showData(data); } //打印数组 private static void showData(int[] data) { for (int i = 0; i < data.length; i++) { System.out.println(data[i]); } } // 直接插入排序 private static void insert_sort(int[] data) { int t; int j; for (int i = 1; i < data.length; i++) {// i表示插入次数,共进行data.length-1次插入 t = data[i];// 把待排序元素赋给t j = i-1; while ((j >= 0) && (t < data[j])) { data[j+1] = data[j]; j--; }// 顺序比较和移动 data[j+1] = t; } } }
排序二:折半插入排序
折半插入排序是对插入排序算法的一种改进,由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
具体操作:在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素小,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。
下面按从小到大排序:
public class Sort { public static void main(String[] args) { int[] data = { 31, 23, 89, 10, 47, 68, 8, 22 }; binarySearchInsertion(data); showData(data); } //打印数组 private static void showData(int[] data) { for (int i = 0; i < data.length; i++) { System.out.println(data[i]); } } private static void binarySearchInsertion(int data[]) { int middle = 0; for (int i = 1; i < data.length; i++) { int low = 0; int high = i - 1; int t = data[i]; while (low <= high) { middle = (low + high) / 2; if (t < data[middle]) { high = middle - 1; }else { low = middle + 1; } } for (int j = i; j > middle; j--) { data[j] = data[j-1]; } data[high + 1] = t;// 此处用data[low] = t;也可 } } }
序列:
31 23 89 10 47 68 8 22
i = 1: 23 31 89 10 47 68 8 22
i = 2: 23 31 89 10 47 68 8 22
i = 3: 10 23 31 89 47 68 8 22
i = 4: 10 23 31 47 89 68 8 22
i = 5: 10 23 31 47 68 89 8 22
i = 6: 8 10 23 31 47 68 89 22
i = 7: 8 10 22 23 31 47 68 89
这样数组从小到大就排序好了。
排序三:希尔排序
希尔排序(Shell Sort)是插入排序的一种。是针对直接插入排序算法的改进。该方法又称缩小增量排序
基本思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
一般的初次取序列的一半为增量,以后每次减半,直到增量为1。
从小到大排序:
public class Sort { public static void main(String[] args) { int[] data = { 31, 23, 89, 10, 47, 68, 8, 22 }; shell(data); showData(data); } //打印数组 private static void showData(int[] data) { for (int i = 0; i < data.length; i++) { System.out.print(data[i] +" "); } } // 希尔排序 private static void shell(int data[]) { int k = data.length / 2;// k值代表前文中的增量d值 , 一般的初次取序列的一半为增量,以后每次减半,直到增量为1 int j; while (k >= 1) {// 当增量k值变化到0,结束循环…… int t; for (int i = k; i < data.length; i++) { t = data[i]; j = i - k; while ((j >= 0) && (t < data[j])) { data[j + k] = data[j]; j = j - k; } data[j + k] = t; } k = k / 2; } } }
序列:
31 23 89 10 47 68 8 22
31 23 89 10 47 68 8 22
31 23 89 10 47 68 8 22
31 23 8 10 47 68 89 22
31 23 8 10 47 68 89 22
8 23 31 10 47 68 89 22
8 10 31 23 47 68 89 22
8 10 31 23 47 68 89 22
8 10 31 23 47 68 89 22
8 10 31 23 47 68 89 22
8 10 31 22 47 23 89 68
8 10 31 22 47 23 89 68
8 10 31 22 47 23 89 68
8 10 22 31 47 23 89 68
8 10 22 31 47 23 89 68
8 10 22 23 31 47 89 68
8 10 22 23 31 47 89 68
8 10 22 23 31 47 68 89
最后排序也就出来了。
排序四:冒泡排序
冒泡排序算法:
1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
3、针对所有的元素重复以上的步骤,除了最后一个。
4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
public class Sort { public static void main(String[] args) { int[] data = { 31, 23, 89, 10, 47, 68, 8, 22 }; bubbleSort(data); showData(data); } // 打印数组 private static void showData(int[] data) { for (int i = 0; i < data.length; i++) { System.out.print(data[i] + " "); } } // 冒泡排序 private static void bubbleSort(int[] data) { boolean exchange;// 交换标志 int t; for (int i = 1; i < data.length; i++) {// 最多做n-1趟排序 exchange = false;// 本趟排序开始前,交换标志应为假 for (int j = 1; j <= data.length - i; j++) { // 对当前无序区R[i..n]自下向上扫描 if (data[j] < data[j - 1]) {// 交换记录 t = data[j]; // t仅做暂存单元 data[j] = data[j - 1]; data[j - 1] = t; exchange = true; // 发生了交换,故将交换标志置为真 } } if (!exchange) {// 本趟排序未发生交换,提前终止算法 return; } } } }
排序五:快速排序
快速排序是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
下面从小到大排序:
public class Sort { public static void main(String[] args) { int[] data = { 31, 23, 89, 10, 47, 68, 8, 22 }; quickSort(data, 0, data.length - 1); showData(data); } // 打印数组 private static void showData(int[] data) { for (int i = 0; i < data.length; i++) { System.out.print(data[i] + " "); } } // 快速排序 private static void quickSort(int[] data, int low, int high) { // 对data[low..high]快速排序,low,high表示下标数 int k; // 划分后的基准记录的位置 if (low < high) { // 仅当区间长度大于1时才须排序 k = quickPass(data, low, high); // 对R[low..high]做划分 quickSort(data, low, k - 1); // 对左区间递归排序 quickSort(data, k + 1, high); // 对右区间递归排序 } } private static int quickPass(int data[], int i, int j) { int t = data[i]; // 用区间的第1个记录作为基准 while (i < j) { // 从区间两端交替向中间扫描,直至i=j为止 while (i < j && data[j] >= t) { // t相当于在位置i上 j--; // 从右向左扫描,查找第1个关键字小于t的记录data[j] } if (i < j) { // 表示找到的data[j]的关键字<t data[i++] = data[j]; // 相当于交换data[i]和data[j],交换后i指针加1 } while (i < j && data[i] <= t) { // t相当于在位置j上 i++; // 从左向右扫描,查找第1个关键字大于t的记录data[i] } if (i < j) { // 表示找到了data[i],使data[i]>t data[j--] = data[i]; // 相当于交换data[i]和data[j],交换后j指针减1 } } data[i] = t; // 基准记录已被最后定位 return i; } }
序列:
交换后:22 23 8 10 31 68 47 89
交换后:10 8 22 23 31 68 47 89
交换后:8 10 22 23 31 68 47 89
交换后:8 10 22 23 31 47 68 89
最后快速排序就结束了,从小到大为:8 10 22 23 31 47 68 89 。