今天说一说数据结构中的排序和查找
我最早遇见也是用过最多的排序就是选择排序。
一、选择排序是一种非常基本的排序算法。其基本思想就是将线性表看成有序和无序两个部分,有序子表是a[0:i-1],无序子表是a[i:n-1]。排序过程中每次从无序子表中选出最小的一个元素,将其添加到有序子表的末尾,有序子表保持有序且长度加1,无序子表长度减1,重复这个过程知道无序子表为空。
不多说,直接看代码:
public void selectSort(int[] a){ if (a==null) return; if (a.length==0) return; //外循环只需循环n-1次 for (int i=0;i<a.length-1;i++){ for (int j = i+1;j<a.length;j++){ if (a[i]>a[j]){ //交换函数 swap(a,i,j); } } } }
因为每循环一次,就有一个数已经有序,所以外循环只需执行n-1次即可。
二、插入排序:同样,也是将线性表看成有序和无序两个部分,有序子表是a[0:i-1],无序子表是a[i:n-1],排序过程中是每次从无序子表中取出一个元素,将其插入到有序子表的正确位置,使有序子表保持有序并逐渐增大,知道所有记录都插入有序表。
看代码:
public void insertSort(int[] a){ if (a==null) return; if (a.length==0) return; for (int i=1;i<a.length;i++){ int x =a[i]; int j; for (j=i-1;j>=0 && a[j]>x;j--) a[j+1] = a[j]; a[j+1] = x; } }
内循环就是为了给无序子表中的元素找到正确的位置,不破坏有序子表的有序性。
三、冒泡排序:与之前的选择排序相比,选择排序一趟下来能找到最小的那个元素,而冒泡排序每趟能找到的是最大的那个元素。冒泡排序将两两相邻的元素进行比较,碰到逆序则交换,直到循环完成。
看代码:
public void bubbleSort(int[] a){ if (a==null) return; if (a.length==0) return; int flag = 1; for (int i=0;i<a.length && flag!=0;i++){ //这里减i是为了提高效率 flag = 0; for (int j = 0;j<a.length-i-1;j++){ if (a[j]>a[j+1]){ swap(a,j,j+1); flag = 1; } } } }
因为每次排序都会有一个元素有序,为了提高效率,避免重复扫描元素,内循环将每次排序后的有序个数减掉。
四、快速排序:又称为分区交换排序,是目前已知的实测平均速度最快的一种排序方法,它是对冒泡排序的一种改进。
看代码吧
public void quickSort(int[] a){ if (a==null) return; if (a.length==0) return; quickSort(a,0,a.length-1); } public void quickSort(int[] a,int low,int high){ if (low>high) return; int k = divide(a,low,high); quickSort(a,low,k-1); quickSort(a,k+1,high); } private int divide(int[] a, int low, int high) { int x = a[low]; while (low<high){ while (low<high && a[high]>=x) high--; a[low] = a[high]; while (low<high && a[low]<x) low++; a[high] = a[low]; } a[low] = x; return low; }
先从后面遍历,如果比第一个值小,则停止,再从前面开始遍历,如果比第一个值大,则停止,知道数组有序。
五、归并排序:归并排序是将两个有序的序列的有序合并。因此将两个有序子序列合并成一个有序序列是归并排序的基础算法。
看代码。。。
public void quickSort(int[] a){ if (a==null) return; if (a.length==0) return; quickSort(a,0,a.length-1); } public void quickSort(int[] a,int low,int high){ if (low>high) return; int k = divide(a,low,high); quickSort(a,low,k-1); quickSort(a,k+1,high); } private int divide(int[] a, int low, int high) { int x = a[low]; while (low<high){ while (low<high && a[high]>=x) high--; a[low] = a[high]; while (low<high && a[low]<x) low++; a[high] = a[low]; } a[low] = x; return low; }
归并排序很稳定,而且效率也很高。
六、堆排序:堆排序是在直接选择排序的基础上借助于堆而形成的一种排序方法。
看代码...
public void heapSort(int[] a){ if (a==null) return; if (a.length==0) return; int len = a.length; buildHeap(a,len); while (len>1){ swap(a,0,len-1); len--; adjustHeap(a,0,len); } } private void adjustHeap(int[] a, int i, int len) { int maxIndex = i; if (2*i < len && a[2*i]>a[maxIndex]) maxIndex = 2*i; if (2*i+1 < len && a[2*i+1]>a[maxIndex]) maxIndex = 2*i+1; if (maxIndex != i){ swap(a,i,maxIndex); adjustHeap(a,maxIndex,len); } } private void buildHeap(int[] a, int len) { for (int i = (len-1)/2;i>=0;i--) adjustHeap(a,i,len); }
其实堆排序只要了解原理就很容易写出来,反正我不喜欢它。
七、计数排序:基数排序就是找出线性表中的最小值和最大值,然后将之间出现的元素放到一个数组中计数,当计数完成,再遍历一遍不就是已经排好序的数据了吗
再说一遍,看代码。。。
public void countSort(int[] a){ if (a==null) return; if (a.length==0) return; int max = a[0],min = a[0]; for (int i=0;i<a.length;i++){ if (a[i]<min) min = a[i]; if (a[i]>max) max = a[i]; } int[] t = new int[max-min+1]; int abs = 0-min; for (int i=0;i<a.length;i++){ t[a[i]+abs]++; } int i = 0,index = 0; while (index<a.length){ if (t[i]!=0){ a[index++] = i-abs; t[i]--; }else { i++; } } }
计数排序很长适用于稳定在某一区间的数据,在这种情况下,时间复杂对和空间复杂度都很惊人
八、二分查找:博主目前能拿出手的就是二分查找了
不说了,心酸,看代码吧
public int binSearch(int[] a,int x){ if (a==null) return -1; if (a.length==0) return -1; int left = 0; int right = a.length-1; int mid = (left+right)/2; while (a[mid]!=x){ if (a[mid]<x){ left = mid+1; }else { right = mid-1; } if (left>right) return -1; mid = (left+right)/2; } return mid; }注意,二分查找的前提数组事先是有序的才行。