上学期学了数据结构这门课,感觉上的太水了,自己再来重温一遍.
一、插入排序
public static void insertSort(int[] a) { int j; for(int p=1;p<a.length;p++) //默认按递增排序 { Integer temp=a[p]; for(j=p;j>0&&temp.compareTo(a[j-1])<0;j--) //主要的一步是将要插入a[j]=a[j-1]; //的元素与之前的元素比较直到找到要插入的位置
a[j]=a[j-1];
a[j]=temp;
}} 时间复杂度O(N2);因为内循环中元素的比较次数对于p的每个值最多是p+1次。//这一步是为了将所有的在被插入位置之后的元素往后挪一位;
二、希尔排序
时间复杂度O(N2);public static void shellsort(int[] a) { int j; for(int increment=a.length/2;increment>0;increment/=2) //increment这里代表的是希尔增量 for(int i=increment;i<a.length;i++) { Integer temp=a[i]; for(j=i;j>=increment&&temp.compareTo(a[j-increment])<0;j-=increment)//这里和插入排序非常相似 a[j]=a[j-increment]; //元素后移的位置不再是相邻的挪移 //而是挪了相隔increment的距离 a[j]=temp; } }
三、堆排序
private static int leftChild(int i) { return 2*i+1; } private static void Down(Integer[] a,int i,int n) { Integer child; Integer temp; for(temp=a[i];leftChild(i)<n;i=child) { child=leftChild(i); if(child!=n-1&&a[child].compareTo(a[child+1])<0)//这一步是为了找到子节点中的较大孩子 child++; if(temp.compareTo(a[child])<0) a[i]=a[child]; else break; } a[i]=temp; //将大节点都按从大到下一层层放下来之后找到合适temp的位置; } public static void heapSort(Integer[] a) {//因为堆是完全二叉树形式的所以我在这把它当作数组来操作了。 for(int i=a.length/2-1;i>=0;i--) Down(a,i,a.length); //类似初始化堆,把最大值给搞到堆顶了。 for(int i=a.length-1;i>0;i--) { int temp=a[0];//实现了将最大值放到堆的最后面的目标; a[0]=a[i]; a[i]=temp; Down(a,0,i); //实现Down的过程中不对把刚放到末尾的的最大值进行操作; } }
时间复杂度为O(N logN);主要时间耗费在构建堆、调整堆上面了,构建堆消耗O(N)的时间,调整堆花了2[log i]的时间,;堆排序是很稳定的
算法。(稳定指的是假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。)
四、归并排序
时间复杂度为O(N logN),在整个算法中还要将tempArray中的数据给拷贝回a中,这里就减慢了速度.private static void mergeSort(Integer[] a,Integer[] tempArray,int left,int right) { if(left<right) { int middle=(left+right)/2; mergeSort(a,tempArray,left,middle); //通过不断的递归,将 mergeSort(a,tempArray,middle+1,right); merge(a,tempArray,left,middle+1,right); } } private static void merge(Integer[] a,Integer[] tempArray,int left,int right,int rEnd) { int lEnd=right-1; int temp=left; int sum=rEnd-lEnd+1; while(left<=lEnd&&right<rEnd)//a中装着两个数组,以right-1为界; if(a[left].compareTo(a[right])<=0)//通过left、right指针的移动来 tempArray[temp++]=a[left++]; //将两部分之中较小的那个放到tempArray中 else tempArray[temp++]=a[right++]; while(left<=lEnd) //若左边没有放完,则继续直接放入即可 tempArray[temp++]=a[left++]; while(right<=rEnd) //若右边没有放完,则继续直接放入即可 tempArray[temp++]=a[right++]; for(int i=0;i<sum;i++,rEnd--) //将tempArray中的值再返回a中 a[rEnd]=tempArray[rEnd]; } public static void mergeSort(Integer[] a) { Integer[] tempArray=(Integer[]) new Comparable[a.length]; mergeSort(a,tempArray,0,a.length-1); }
五、快速排序
快排对pivot的选取比较关键,在一串随机生成的数字中,枢纽可以选在开头,也可选在末尾;但,是如果是一串刚好已经排为相反方向的的数组进行快排时,这就很尴尬了,public static void quicksort(int[] ar, int start, int end){ int[] array; int i = start, j = end; if (end-start >= 1){ int pivot = ar[end]; while (i< j){ while (ar[i]<pivot && i<end){ i++; } while (ar[j]>=pivot && j>start){ j--; } if (i<j){ swap(ar, i, j); } } swap(ar, end, i); quicksort(ar, start, i-1); quicksort(ar, i+1, end); } else{ return; } } public static void swap(int[] ar, int index1, int index2){ int temp = ar[index1]; ar[index1] = ar[index2]; ar[index2] = temp; }
快排的时间复杂度为O(NlogN);
六、桶排序与基数排序上面这个例子是关于字符串的基数排序的实现,用一个ArrayList做桶。时间复杂度public static void radixSortA(String[] arr,int stringLen) { final int BUCKETS=256; ArrayList<String> [] buckets=(ArrayList<String> [])new ArrayList[BUCKETS]; for(int i=0;i<BUCKETS;i++) buckets[i]=new ArrayList<>(); for(int pos=strLen-1;pos>=0;pos--) { for(String s:arr) buckets[s.charAt(pos)].add(s); int idx=0; for(ArrayList<String> thisBucket:buckets) { for(String s:thisBucket) arr[idx++]=s; thisBucket.clear(); } } }
O(NL),这里桶的设定是假设所有字符都是ASCII码,位于Unicode字符集的前256位。
若有不正确之处,望大家指证。