潍坊市建设局网站,深圳网站建设学校,wordpress5.2.2中文,网站建设课程设计论文目录
排序的概念#xff1a;
排序算法的实现#xff1a;
插入排序#xff1a;
希尔排序#xff1a;
选择排序#xff1a;
堆排序#xff1a;
冒泡排序#xff1a;
快速排序#xff1a;
快速排序的基本框架#xff1a;
1.Hoare法
2. 挖坑法
3.前后指针法 快…目录
排序的概念
排序算法的实现
插入排序
希尔排序
选择排序
堆排序
冒泡排序
快速排序
快速排序的基本框架
1.Hoare法
2. 挖坑法
3.前后指针法 快排的优化
1. 三数取中法选key
2. 小区间使用插入排序
优化代码
常见问题
归并排序
总结
结语 排序的概念
排序
所谓排序就是使一串记录按照其中的某个或某些关键字的大小递增或递减的排列起来的操作。
稳定性
假定在待排序的记录序列中存在多个具有相同的关键字的记录若经过排序这些记录的相对次序保持 不变即在原序列中r[i]r[j]且r[i]在r[j]之前而在排序后的序列中r[i]仍在r[j]之前则称这种排序算法是稳 定的否则称为不稳定的稳定可以转换成不稳定的不稳定不可以转换成稳定的。
内部排序
数据元素全部放在内存中的排序。
外部排序
数据元素太多不能同时放在内存中根据排序过程的要求不能在内外存之间移动数据的排序。
常见的排序算法
直接插入排序希尔排序选择排序堆排序冒泡排序快速排序归并排序。
排序算法的实现
说明由于swap函数经常出现为了使文章更加整洁这里给出源码下文直接调用不在说明。 private static void swap(int[] array,int i,int j){int tmp array[i];array[i] array[j];array[j] tmp;}
插入排序
思路在待排序的元素中假设前n-1个元素已有序现将第n个元素插入到前面已经排好的序列中使得前n个元素有序。按照此法对所有元素进行插入直到整个序列有序。
动图演示如下 代码实现如下 public static void insertSort(int[] array){for(int i 1;i array.length; i){int j i-1;int tmp array[i];for(;j 0; j--){if(array[j] tmp){array[j1] array[j];}else{break;}}array[j1] tmp;}}
结果演示 直接插入排序的特性总结 1. 元素集合越接近有序直接插入排序算法的时间效率越高 2. 时间复杂度O(N^2) 3. 空间复杂度O(1)它是一种稳定的排序算法 4. 稳定性稳定 希尔排序
思路希尔排序法又称缩小增量法。希尔排序法的基本思想是先选定一个整数把待排序文件中所有记录分成多个组所有距离为的记录分在同一组内并对每一组内的记录进行排序。然后取重复上述分组和排序的工作。当到达 1时所有记录在统一组内排好序。
动图演示 代码实现如下
在shellSort里面确定组的大小在shell里面进行排序通过计算确定gap的关系间隔运行一次通过。 public static void shellSort(int[] array){int gap array.length;while(gap 1){gap / 2;shell(array,gap);}}public static void shell(int[] array,int gap){for(int i gap; i array.length; i){int j 0;j i-gap;int tmp array[i];for(;j 0;j - gap){if(array[j] tmp){array[jgap] array[j];}else{break;}}array[jgap] tmp;}}
结果演示 希尔排序的特性总结 1. 希尔排序是对直接插入排序的优化。 2. 当gap 1时都是预排序目的是让数组更接近于有序。当gap 1时数组已经接近有序的了这样就会很 快。这样整体而言可以达到优化的效果。我们实现后可以进行性能测试的对比。 3. 希尔排序的时间复杂度不好计算因为gap的取值方法很多导致很难去计算因此在好些树中给出的希尔排 序的时间复杂度都不固定。 4. 稳定性不稳定 选择排序
思路
1在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素。
2若它不是这组元素中的最后一个(第一个)元素则将它与这组元素中的最后一个第一个元素交换。
3在剩余的array[i]--array[n-2]array[i1]--array[n-1]集合中重复上述步骤直到集合剩余1个元素。
动图演示 代码实现如下 //选择排序public static void selectSort(int[] array){for(int i 0;i array.length-1; i){int minIndex i;for(int j i1;j array.length; j){if(array[j] array[minIndex]){minIndex j;}}swap(array,i,minIndex);}}private static void swap(int[] array,int i,int j){int tmp array[i];array[i] array[j];array[j] tmp;}
结果演示 选择排序的特性总结 1. 直接选择排序思考非常好理解但是效率不是很好。实际中很少使用 2. 时间复杂度O(N^2) 3. 空间复杂度O(1) 4. 稳定性不稳定 堆排序
思路堆排序(Heapsort)是指利用堆积树堆这种数据结构所设计的一种排序算法它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆排降序建小堆。
动图演示 代码实现如下
从小到大用大根堆
从大到小用小根堆
下面代码为大根堆 public static void heapSort(int[] array){createBigHeap(array);int end array.length-1;while(end 0){swap(array,0,end);siftDown(array,0,end);end--;}}private static void createBigHeap(int[] array){for(int parent (array.length - 1 -1)/2; parent 0; parent--){siftDown(array,parent,array.length);}}private static void siftDown(int[] array,int parent,int end){int child parent*21;while(child end) {if (child 1 end array[child] array[child 1]) {child;}if (array[child] array[parent]) {swap(array, child, parent);parent child;child parent * 2 1;} else {break;}}} 结果演示 堆排序的特性总结 1. 堆排序使用堆来选数效率就高了很多。 2. 时间复杂度O(N*logN) 3. 空间复杂度O(1) 4. 稳定性不稳定 冒泡排序
简单就不给思路了
动图演示 代码实现如下
public static void bubbleSort(int[] array){for(int i 0; i array.length - 1; i){boolean flg false;for(int j 0; j array.length-1-i; j){if(array[j] array[j1]){swap(array,j,j1);flg true;}}if(flg false){return;}}} 结果演示 冒泡排序的特性总结 1. 冒泡排序是一种非常容易理解的排序 2. 时间复杂度O(N^2) 3. 空间复杂度O(1) 4. 稳定性稳定 快速排序
思路任取待排序元素序列中的某元 素作为基准值按照该排序码将待排序集合分割成两子序列左子序列中所有元素均小于基准值右子序列中所有元素均大于基准值然后最左右子序列重复该过程直到所有元素都排列在相应位置上为止。
快速排序的基本框架 //快排的框架public static void quickSort(int[] array,int left,int right){if(right left){return;}int div partition(array,left,right);quickSort(array,left,div-1);quickSort(array,div1,right);}
这是还没优化的。
partition可以得到left和right相遇的下标。
关于partition有三种求法分别是Hoare版挖坑法前后指针。
其中最常用的是挖坑法。
1.Hoare法
动图如下 代码实现 //Hoareprivate static int partition(int[] array,int left,int right){int i left;int j right;int pivot array[left];while(j i){while(j i array[j] pivot){j--;}while(j i array[i] pivot){i;}swap(array,i,j);}swap(array,i,left);return i;}
2. 挖坑法
动图如下 代码实现
//挖坑法private static int partition(int[] array,int left,int right){int i left;int j right;int pivot array[left];while(j i){while(j i array[j] pivot){j--;}array[i] array[j];while(j i array[i] pivot){i;}array[j] array[i];}array[i] pivot;return i;}
3.前后指针法 代码如下 //前后指针法private static int partition(int[] array,int left,int right){int prev left;int cur left1;while(cur right){if(array[cur] array[left] array[prev] ! array[cur]){swap(array,cur,prev);}cur;}swap(array,prev,left);return prev;} 快排的优化
1. 三数取中法选key
使用该优化方法可以有效减少当数组有序时变成单叉树的时间复杂度。
基本思路选取数组中第一个数中间数和最后一个数比较大小将其中中间值和最左边交换这样可以使mid左后两边数组个数尽可能相等。
代码如下
private static int middleNum(int[] array,int left,int right){int mid left ((right - left) 1);if(array[left] array[right]){if(array[mid] array[left]){return left;}else if(array[mid] array[right]){return mid;}else{return right;}}else{if(array[mid] array[right]){return right;}else if(array[mid] array[left]){return mid;}else{return left;}}}
2. 小区间使用插入排序
思路我们直到插入排序在数组接近有序时是非常快的而快排最后在堆上调用的空间是非常大的故在小区间上使用插入排序可以达到优化的效果。
代码如下
//优化1if(right - left 1 15){insertSort2(array,left,right);return;}private static void insertSort2(int[] array,int left,int right){if(left right){return;}for(int i 1 left;i right;i){int tmp array[i];//都定义可读性好int j i-1;for(;j left;j--){if(array[j] tmp){array[j1] array[j];}else{break;}}array[j1] tmp;}}
优化代码
为节省文章长度下面个代码在上面给出下面我就不给总代码了抱歉。
public static void quickSort(int[] array,int left,int right){if(right left){return;}//优化1if(right - left 1 15){insertSort2(array,left,right);return;}//优化2int index middleNum(array,left,right);swap(array,index,left);int div partition(array,left,right);quickSort(array,left,div-1);quickSort(array,div1,right);} 快速排序的特性总结 1. 快速排序整体的综合性能和使用场景都是比较好的所以才敢叫快速排序 2. 时间复杂度O(N*logN 3. 空间复杂度O(logN) 4. 稳定性不稳定 常见问题
1.在partition 方法中array[j] pivot 和 array[i] pivot中的等号能否去掉
答不能因为当left和right下标的值等于pivot时会陷入死循环。
2.在partition 方法中能不能先从left开始遍历
答不能因为这样最后和第一个数交换时会把比pivot大的数给到第一个假设取得pivot取的都是第一个数
归并排序
思路归并排序MERGE-SORT是建立在归并操作上的一种有效的排序算法,该算法是采用分治法Divide and Conquer的一个非常典型的应用。将已有序的子序列合并得到完全有序的序列即先使每个子序列有序再使 子序列段间有序。若将两个有序表合并成一个有序表称为二路归并。
图片如下 代码实现
先拆分后合并用递归实现拆分merge实现合并。
//归并排序public static void mergeSort(int[] array,int left,int right){if(left right){return;}int mid left ((right - left) 1);mergeSort(array,left,mid);mergeSort(array,mid1,right);merge(array,left,mid,right);}private static void merge(int[] array,int left,int mid,int right){int s1 left;int s2 mid 1;int e1 mid;int e2 right;int k 0;int[] tmpArr new int[right - left 1];while(s1 e1 s2 e2){if(array[s1] array[s2]){tmpArr[k] array[s1];}else{tmpArr[k] array[s2];}}while(s1 e1){tmpArr[k] array[s1];}while(s2 e2){tmpArr[k] array[s2];}for(int i 0;i k;i){array[i left] tmpArr[i];//特别注意要加left}} 归并排序总结 1. 归并的缺点在于需要O(N)的空间复杂度归并排序的思考更多的是解决在磁盘中的外排序问题。 2. 时间复杂度O(N*logN) 3. 空间复杂度O(N) 4. 稳定性稳定 总结
重点掌握快排堆排归并插入。
计数基数桶这三个排序了解即可代码不会写都没事不考的 结语
其实写博客不仅仅是为了教大家同时这也有利于我巩固自己的知识点和一个学习的总结由于作者水平有限对文章有任何问题的还请指出接受大家的批评让我改进如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注这可以激励我写出更加优秀的文章。