当前位置: 首页 > wzjs >正文

东莞市网站建设服务机构网站的优化seo

东莞市网站建设服务机构,网站的优化seo,山西省确诊病例最新情况,广州网站开发技术目录 8、快速排序 8.1、Hoare版 8.2、挖坑法 8.3、前后指针法 9、快速排序优化 9.1、三数取中法 9.2、采用插入排序 10、快速排序非递归 11、归并排序 12、归并排序非递归 13、排序类算法总结 14、计数排序 15、其他排序 15.1、基数排序 15.2、桶排序 8、快速排…

目录

8、快速排序

8.1、Hoare版

8.2、挖坑法

8.3、前后指针法

9、快速排序优化

9.1、三数取中法

9.2、采用插入排序

10、快速排序非递归

11、归并排序

12、归并排序非递归

13、排序类算法总结

14、计数排序

15、其他排序

15.1、基数排序

15.2、桶排序


8、快速排序

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法

基本思想:任取待排序元素序列中的某元 素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有 元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止

8.1、Hoare版

1. 把第一个值作为基准值 pivot

2. right 从右边走,遇到比 pivot 大的就停下;left 从左边走,遇到比 pivot 小的就停下

3. 交换 left 和 right 的值

4. left 和 right 继续走,直到 left 和 right 相遇

5. 相遇的位置就是要找的位置,把基准值与该位置交换

    public static void quickSort(int[] array) {quick(array,0,array.length-1);}private static void quick(int[] array,int start,int end) {if(start >= end) {return;}int pivot = partitionHoare(array,start,end);quick(array,start,pivot-1);quick(array,pivot+1,end);}private static int partitionHoare(int[] array, int left, int right) {int tmp = array[left];int pivot = left;while (left < right) {// 单独的循环 不能一直减到超过最左边的边界while (left < right && array[right] >= tmp) {right--;}while (left < right && array[left] <= tmp) {left++;}swap(array,left,right);}swap(array,pivot,left);return left;}

两个问题:

1. 为什么 array[right] >= tmp 必须带等于号

        可能会出现 left 和 right 无限交换的死循环

2. 为什么从 right 先走而不是 left

        如果 left 先走可能会出现相遇的是比基准大的数据,最后把大的数据放到了最前面

快速排序总结:

1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

2. 时间复杂度:O(N*logN)

        最好的情况下:O(N*logN)

        最坏情况下:O(N^2)  -- 逆序/有序

3. 空间复杂度:O(logN)  -- 递归了logN层

        最好的情况下:O(logN)

        最坏情况下:O(N)   -- 逆序/有序

4. 稳定性:不稳定

8.2、挖坑法

1. 把第一个值拿出来作为基准值 tmp,第一个值的位置就是第一个坑

2. right 从右边走,遇到比 pivot 大的就停下,然后把这个值放到上一个坑里,right 就形成了新的坑

3. left 从左边走,遇到比 tmp 小的就停下,然后把这个值放到坑里,left 就是新的坑

4. 循环2、3,直到 left 和 right 相遇

5. 相遇的位置就是要找的位置,把基准值放在这个位置

    public static void quickSort(int[] array) {quick(array,0,array.length-1);}private static void quick(int[] array,int start,int end) {if(start >= end) {return;}int pivot = partitionHole(array,start,end);quick(array,start,pivot-1);quick(array,pivot+1,end);}private static int partitionHole(int[] array, int left, int right) {int tmp = array[left];while (left < right) {// 单独的循环 不能一直减到超过最左边的边界while (left < right && array[right] >= tmp) {right--;}array[left] = array[right];while (left < right && array[left] <= tmp) {left++;}array[right] = array[left];}array[left] = tmp;return left;}

8.3、前后指针法

1. 定义两根指针cur和prev,初始位置如下图

2. cur开始往后走,如果遇到比key小的值,则++prev,然后交换prev和cur指向的元素,再++cur,如果遇到比key大的值,则只++cur

3. 当cur访问过最后一个元素后,将key的元素与prve访问的元素交换位置。cur访问完整个数组后的各元素位置如下图

private static int partition(int[] array, int left, int right) {int prev = left ;int cur = left+1;while (cur <= right) {if(array[cur] < array[left] && array[++prev] != array[cur]) {swap(array,cur,prev);}cur++;}swap(array,prev,left);return prev;
}

总结:
1. Hoare
2. 挖坑法
3. 前后指针法
这3种方式  每次划分之后的前后顺序 有可能是不一样的

9、快速排序优化

优化的出发点:减少递归的次数

9.1、三数取中法

既然有序数组或者有序数组片段会使效率下降,我们就可以让基准值每次都取大小靠中的数,然后在进行快速排序这样就可以避免了。但不是完全避免,只是减少了最坏情况出现的概率,最坏情况还是O(n²),但有效提升了运行效率,主要提升的部分是数组中有序的数组片段,减少了循环次数。

    // 求中位数的下标private static int middleNum(int[] array,int left,int right) {int mid = (left+right)/2;if(array[left] < array[right]) {if(array[mid] < array[left]) {return left;}else if(array[mid] > array[right]) {return right;}else {return mid;}}else {//array[left] > array[right]if(array[mid] < array[right]) {return right;}else if(array[mid] > array[left]) {return left;}else {return mid;}}}private static void quick(int[] array,int start,int end) {if(start >= end) {return;}//1 2 3 4 5 6 7int index = middleNum(array,start,end);swap(array,index,start);//4 2 3 1 5 6 7int pivot = partition(array,start,end);quick(array,start,pivot-1);quick(array,pivot+1,end);}

9.2、采用插入排序

往往一棵树的最后两层的结点占整棵树的绝大多数,所以当递归到一定深度时,采用直接插入排序

    public static void insertSort(int[] array,int left,int right) {for (int i = left+1; i <= right; i++) {int tmp = array[i];int j = i-1;for (; j >= left ; j--) {if(array[j] > tmp) {array[j+1] = array[j];}else {break;}}array[j+1] = tmp;}}private static void quick(int[] array,int start,int end) {if(start >= end) {return;}if(end - start + 1 <= 15) {insertSort(array, start, end);return;}//1 2 3 4 5 6 7int index = middleNum(array,start,end);swap(array,index,start);//4 2 3 1 5 6 7int pivot = partition(array,start,end);quick(array,start,pivot-1);quick(array,pivot+1,end);}

10、快速排序非递归

1. 先调用partition方法找到基准
2. 基准左边和右边有没有2个及以上个元素,有就把下标放到栈中

3. 判断栈空不空,不空出栈2个,第一个是新的end,第二个是新的start

4. 栈不为空时,循环执行上述1.2.3

    public static void quickSortNor(int[] array) {int start = 0;int end = array.length-1;Stack<Integer> stack = new Stack<>();int pivot = partition(array,start,end);if(pivot > start+1) {stack.push(start);stack.push(pivot-1);}if(pivot+1 < end) {stack.push(pivot+1);stack.push(end);}while (!stack.isEmpty()) {end = stack.pop();start = stack.pop();pivot = partition(array,start,end);if(pivot > start+1) {stack.push(start);stack.push(pivot-1);}if(pivot+1 < end) {stack.push(pivot+1);stack.push(end);}}}

11、归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

    public static void mergeSort(int[] array) {mergeSortFun(array,0,array.length-1);}private static void mergeSortFun(int[] array,int start,int end) {if(start >= end) {return;}int mid = (start+end)/2;mergeSortFun(array,start,mid);mergeSortFun(array,mid+1,end);//合并merge(array,start,mid,end);}private static void merge(int[] array, int left, int mid, int right) {// s1,e1,s2,e2 可以不定义,这样写为了好理解int s1 = left;int e1 = mid;int s2 = mid+1;int e2 = right;//定义一个新的数组int[] tmpArr = new int[right-left+1];int k = 0;//tmpArr数组的下标//同时满足 证明两个归并段 都有数据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++];}//把排好序的数据 拷贝回原来的数组array当中for (int i = 0; i < tmpArr.length; i++) {array[i+left] = tmpArr[i];}}

两个有序数组合并为一个有序数组代码:

public static int[] mergeArray(int[] arrayl,int[] array2) {// 注意判断参数int[] tmp = new int[array1.length+array2.length];int k = 0;int s1 = 0;int el = array1.length-1;int s2 = 0;int e2 = array2.length-1;while (s1 <= el && s2 <= e2) {if(array1[s1] <= array2[s2]) {tmp[k++] = array1[s1++];}else {tmp[k++]=array2[s2++];}}while (s1 <= el) {tmp[k++] = array1[s1++];}while (s2 <= e2) {tmp[k++]= array2[s2++];}return tmp;
}

归并排序总结
1. 归并的缺点在于需要O(N)的空间复杂度,归并排序更多的是解决在磁盘中的外排序问题。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(N)

        ‌递归调用栈空间:O(logN)

        合并操作空间:O(N)
4. 稳定性:稳定


海量数据的排序

外部排序:排序过程需要在磁盘等外部存储进行的排序
前提:内存只有 1G,需要排序的数据有 100G
因为内存中因为无法把所有数据全部放下,所以需要外部排序,而归并排序是最常用的外部排序
1. 先把文件切分成 200 份,每个 512 M
2. 分别对 512 M 排序,因为内存已经可以放的下,所以任意排序方式都可以
3. 进行2路归并,同时对 200 份有序文件做归并过程,最终结果就有序了(在外部存储进行)

12、归并排序非递归

1. 找到 left、mid、right 的位置和关系,然后调用merge合并

2. 定义 gap 表示当前的分组是每组几个数据

    public static void mergeSortNor(int[] array) {int gap = 1;//每组几个数据while (gap < array.length) {for (int i = 0; i < array.length; i = i+gap*2) {int left = i;// mid、right 可能会越界int mid = left+gap-1;int right = mid+gap;if(mid >= array.length) {mid = array.length-1;}if(right >= array.length) {right = array.length-1;}merge(array,left,mid,right);}gap*=2;}

13、排序类算法总结

14、计数排序

思想:计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。 操作步骤:
1. 统计相同元素出现次数
2. 根据统计的结果将序列回收到原来的序列中

具体实现:

1.申请一个数组count,大小为待排序数组array的范围 M

2.遍历待排序数组array,把数字对应的count数组的下标内容进行++

3.遍历计数数组count 写回到待排序数组array,此时需要注意写的次数和元素值要一样

4. 最后数组array中存储的就是有序的序列

    public static void countSort(int[] array) {//求数组的最大值 和 最小值  O(N)int minVal = array[0];int maxVal = array[0];for (int i = 1; i < array.length; i++) {if(array[i] < minVal) {minVal = array[i];}if(array[i] > maxVal) {maxVal = array[i];}}//确定计数数组的 长度int len = maxVal - minVal + 1;int[] count = new int[len];//遍历array数组 把数据出现的次数存储到计数数组当中   O(N)for (int i = 0; i < array.length; i++) {count[array[i]-minVal]++;}//计数数组已经存放了每个数据出现的次数//遍历计数数组 把实际的数据写回array数组  O(M) M表示数据范围int index = 0;for (int i = 0; i < count.length; i++) {while (count[i] > 0) {//这里需要重写写回array 意味着得从array的0位置开始写array[index] = i+minVal;index++;count[i]--;}}}

计数排序的特性总结
1.计数排序是非基于比较的排序

2. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限;计数排序的场景:指定范围内的数据

3. 时间复杂度:O(MAX(N,M))   M表示数据范围
4. 空间复杂度:O(M)
5. 稳定性:稳定;上述代码是不稳定的写法

15、其他排序

15.1、基数排序

基数排序(Radix Sort)是一种非比较型的排序算法,它通过逐位比较元素的每一位(从最低位到最高位)来实现排序。基数排序的核心思想是将整数按位数切割成不同的数字,然后按每个位数分别进行排序。基数排序的时间复杂度为 O(d*(n+r)),其中 n 为元素个数,d 是最大数字的位数,r 为基数(桶的个数)

时间复杂度分析:

分配依次将每个数放到对应的桶中 O(n)

收集依次将每个桶里的元素拿出来 O(r)  (桶里的元素是用链表连接的)

每轮:分配+收集 O(n+r)

如果最大的数字有d位,就需要排d轮

所以时间复杂度为:O(d*(n+r))

15.2、桶排序

算法思想:划分多个范围相同的区间,每个子区间自排序,最后合并

计数排序、基数排序、桶排序 都是非基于比较的排序

http://www.dtcms.com/wzjs/517315.html

相关文章:

  • 美食网页设计作品欣赏郑州网站seo技术
  • 收藏网站的代码重庆森林台词
  • 做家宴网站网络测试
  • 网站建设模版文档百度云登陆首页
  • 自己做的网站打开是乱码网络推销
  • 佛山有那些定制网站建设公司新闻最近的新闻
  • 网站建设与管理维护说课优化师培训
  • 外贸电子商务网站网站备案流程
  • 怎么将自己做的网站发到网上去免费软文推广平台都有哪些
  • 如何做搜索引擎网站seo排名优化
  • 企业做的网站推广方案的步骤百度搜图匹配相似图片
  • 海口企业网站建设企业营销策划方案
  • 成功备案的网站增加域名网络营销第三版课本
  • 唐山外贸网站建设佛山今日头条
  • 做网站找哪家好?聚禄鼎科技是一家给企业做网站的公司广告类的网站
  • 如何帮助网站吸引流量昆明长尾词seo怎么优化
  • 网站被做跳转怎么办网页生成
  • 网站开发设计文档模板广州网站优化公司如何
  • 模拟网站效果广安网站seo
  • 网站优化具体做哪些事情windows优化大师怎么卸载
  • 网站开发详细流程站长工具收录查询
  • 盛大正版传奇世界手游品牌搜索引擎服务优化
  • 迅美网站建设网站收录查询
  • 浙江微信网站建设报价百度移动版
  • 做网站用买服务器码谷歌优化排名怎么做
  • 主题资源网站建设步骤西安计算机培训机构哪个最好
  • 企业网站优化系统广州网站建设费用
  • 雅奇小蘑菇做网站好不好用seosem是什么职位
  • 建设个人网站刷有效的网络推广
  • 做封面的软件ps下载网站软文有哪些发布平台