排序算法代码整理
注:以下均为升序排序;
简单排序:
冒泡排序:相邻的元素两两比较,将最大的数放在右边。
int n; long[] theArray = new long[n]; public void bubbleSort(){ for (int out = n-1 ; out > 1 ; out--){ for (int in = 0 ; in < out ; in++){ if (theArray[in] > theArray[in+1]){ swap(in,in+1); } } } } public void swap(int x,int y){ long temp = theArray[x]; theArray[x] = theArray[y]; theArray[y] = temp; }
选择排序:选定第一个元素暂且认为是最小的,依次与剩下的元素比较有比其小的则交换,再交换到第一个位置;然后再定义第二个为次最小的重复上述步骤;
public void selectSort(){ for (int out = 0 ; out < n-1 ; out ++){ int min = out ; for (int in = out + 1 ; in < n ; in++){ if (theArray[in] < theArray[min]){ min = in; } swap(min,out); } } }
选择排序和冒泡排序的比较次数是一样的都是n的平方次,但是选择排序的交换次数要比冒泡排序的交换次数少。选择排序最大的交换次数为n-1,冒泡排序交换的最大次数为(n-1)!次,所以在n很大的时候选择选择排序,在n很小的时候,如果比较的时间级比交换的时间级小也可以选择选择排序。
插入排序:插入排序适合待排序数组中有一部分已经是有序的数组,找到没有序的边界后,将其依次的向前(后)交换到左边大(小)右边小(大)的位置,复制的次数太多了,才能找到暂时的正确位置。
public void insertSort(){ for (int out = 1 ; out < n ; out++){ long temp = theArray[out]; int in = out; while(in >0 && theArray[in-1] > temp){ theArray[in] = theArray[in-1]; --in; } theArray[in] = temp; } }
归并排序:现将待排序的数组从中间划分成两部分,然后递归将原数组一直到划分为每个数组只有一个元素或两个元素,再依次将划分好的数组两两有序的合并到一个数组,直到全部有序的合并。
public void mergeSort(){ long[] workSpace = new long[n]; recMergeSort(workSpace,0,n-1); } public void recMergeSort(long[] workSpace,int lowerBound,int upperBound){ int mid = (lowerBound + upperBound)/2; recMergeSort(workSpace,lowerBound,mid);//递归 recMergeSort(workSpace,mid+1,upperBound); merge(workSpace,lowerBound,mid+1,upperBound);//合并 } public void merge(long[] workSpace,int lowerPtr,int highPtr,int upperBound){ int lowerBound = lowerPtr; int mid = highPtr - 1; int n = lowerBound + upperBound -1; int j =0; while(lowerPtr <= mid && highPtr <= upperBound){ if (theArray[lowerPtr] < theArray[highPtr]){ workSpace[j++] = theArray[lowerPtr++]; } else { workSpace[j++] = theArray[highPtr++]; } } while(lowerPtr <= mid){ workSpace[j++] = theArray[lowerPtr++];//中后半部分比中前半部分短 } while (highPtr <= upperBound){ workSpace[j++] = theArray[highPtr++];//中前半部分比中后半部分短 } for (int i = 0 ; i < n ; i++){ theArray[lowerBound+i] = workSpace[i]; } }
高级排序:
希尔排序:原理与插入排序一致,不同点就是增加一个间隔序列h=h*3+1(1,4,13,40,121,364...)。
public void shellSort(){ int h = 1; while(h <= n/3){ h = h*3 +1; } while(h > 0){ for (int out = h ;out < n ; out++){ long temp = theArray[out]; int in = out; while(in > h-1 && theArray[in-h] > temp){ theArray[in] = theArray[in-h]; in-=h; } theArray[in] = temp; } h = (h-1)/3; } }
快速排序:将待排序的数组,划分成一边是比选出来的比较值小(大)一边是比比较值小(大),依次采用递归的方式最后为有序的数组。
public void quickSort(){ recQuickSort(0,n-1); } public void recQuickSort(int left,int right){ int size = left + right - 1; if (size <= 3){ manualSort(left,right);//选用“三个数据项取中”的方式选出一个比较值,是了避免选中的比较值太小或太大; } else{ long media = medianOf3(left,right); int partition = partitionIt(left,right,media); recQuickSort(left,partition); recQuickSort(partition+1,right); } } public int partitionIt(int left,int right,long media){ int leftPtr = left -1; int rightPtr = right; while(true){ while (theArray[++leftPtr] < media); while (theArray[--rightPtr] > media); if (leftPtr >= rightPtr){ break; }else{ swap(leftPtr,rightPtr); } } swap(leftPtr,right); return leftPtr; } public long medianOf3(int left,int right){ int mid = (left+right)/2; if (theArray[left] > theArray[mid]){ swap(left,mid); } if (theArray[mid] > theArray[right]){ swap(mid,right); } if (theArray[left] > theArray[right]){ swap(left,right); } swap(mid,right); return theArray[right]; } public void manualSort(int left, int right){ int size = left + right - 1; if (size <= 1){ return; } if (size ==2){ if (theArray[left] > theArray[right]){ swap(left, right); } return; } else{ if (theArray[left] > theArray[right - 1]) { swap(left, right -1); } if (theArray[left] > theArray[right]){ swap(left, right); } if (theArray[right - 1] > theArray[right]) { swap(right-1,right); } } }
堆排序:
根据初始数组构造大顶堆(大顶堆:每个节点的关键字大于等于子节点的关键字,升序采用大顶推;小顶堆:每个节点的关键字小于等于子节点的关键字,降序采用小顶推);
每次交换大顶堆的第一个和最后一个元素,推出最后一个元素,然后把剩下的元素重新调整为大顶堆。
public void HeapAdjust(int[] array, int parent, int length) { int temp = array[parent]; // temp保存当前父节点 int child = 2 * parent + 1; // 先获得左孩子 while (child < length) { if (child + 1 < length && array[child] < array[child + 1]) { child++;// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点 } if (temp >= array[child])// 如果父结点的值已经大于孩子结点的值,则直接结束 break; array[parent] = array[child];// 把孩子结点的值赋给父结点 parent = child;// 选取孩子结点的左孩子结点,继续向下筛选 child = 2 * child + 1; } array[parent] = temp; } public void heapSort(int[] list) { for (int i = list.length / 2; i >= 0; i--) {// 循环建立初始堆 HeapAdjust(list, i, list.length - 1); } for (int i = list.length - 1; i > 0; i--) { int temp = list[i]; // 最后一个元素和第一元素进行交换 list[i] = list[0]; list[0] = temp; HeapAdjust(list, 0, i);// 筛选 R[0] 结点,得到i-1个结点的堆 } }
各种排序的时间复杂度与空间复杂度: