ReviewForJob——快速排序(基于插入排序)+快速选择(快速排序变体)

【0】README

0)本文旨在给出 快速排序 的 源码实现和源码分析(分析它的坑);

2)要知道 在 元素个数小于10的时候,快速排序不如插入排序;注意快速排序选取枢纽元 时 所使用的方法是 三数中值分割法,截止范围为10(也就是,如果排序的数组个数小于10, 就不选择快速排序, 而是选择其他排序方法, 如希尔排序或插入排序);(不能再干货)

3)因为 快速排序是基于分治的,这里通过递归实现了分治,每次递归后,待排序的元素个数都会减少,所以最后都是通过插入排序来完成排序的;

4)快速排序基础 参见http://blog.csdn.net/pacosonswjtu/article/details/48879419, 插入排序基础参见 http://blog.csdn.net/pacosonswjtu/article/details/48879263

Attention)小生的插入排序以 本文中的 插入排序为准,以前写的都不算数(哈哈),因为我发现这个 版本的插入排序太 tm 灵活了,仅此而已;

5)快速选择算法(从n个数中选择第k个最大(小)数),代码实现在文末;快速选择算法 基础知识 参见 http://blog.csdn.net/pacosonswjtu/article/details/48915197


【1】上源码

#include <stdio.h>
#include <malloc.h>#define ElementType intvoid swap(ElementType* a, ElementType* b);
ElementType median3(ElementType* array, int left, int right);
void quicksort(ElementType* array, int left, int right);
void printArray(ElementType* array, int N);
void insertionSort(ElementType* array, int left, int right);// swap array arraynd b.
void swap(ElementType* array, ElementType* b)
{ElementType t;t=*array;*array=*b;*b=t;
}// 3数中值分割法 选出 left center right 分别存储最小,中间,最大值
// 然后 将中位数隐藏到倒数第2个元素 
ElementType median3(ElementType* array, int left, int right)
{	int center = (left+right)/2;if(array[left]>array[center]){swap(&array[left], &array[center]);	}if(array[left]>array[right]){swap(&array[left], &array[right]);	}if(array[center]>array[right]){swap(&array[center], &array[right]);	}/* 将中位数隐藏到倒数第2个元素 */swap(&array[center], &array[right-1]);return array[right-1];
}/* 快速排序 */
void quicksort(ElementType array[], int left, int right)
{int i, j;ElementType pivot; // 枢轴.// if(right-left >= 10) { also you can let lower limit be 10.if(right-left >= 3) { /* rihgt-left>=3,才有三数中值分割法的应用 *//* 三数分割 median3 把最大元放入array[right]了,枢纽元放入array[right-1],最小元放入array[left] */pivot = median3(array, left, right);    i = left; //i 指向最小元.j = right-1; // j 指向枢纽元.for(;;) {while(array[++i] < pivot);    /* (这里必须++i, 不能i++)找大元素,i停在那里,i起始从 left+1 */while(array[--j] > pivot);    /* (这里必须--j, 不能j--)找小元素,j停在那里,j起始从 right-2 */if(i<j){swap(&array[i], &array[j]);    /* 分割结束 */}else{break;}}//key: array[i]最后指向大元素,array[right-1]指向枢纽元,将它们交换;		swap(&array[i], &array[right-1]);  // 交换后, array[i]=枢纽元, 前面的元素小于它, 后面的元素大于它.quicksort(array, left, i-1);  		/* 递归进行快速排序 */quicksort(array, i+1, right);		/* 递归进行快速排序 */} else	/* 当数组长度小于cutoff-隔断距离的话,那么就采用插入排序,因为这样效率高些*/{insertionSort(array, left, right);}
}// 插入排序
void insertionSort(ElementType* array, int left, int right)
{int i, j;ElementType temp;	for(i=left+1; i<=right; i++) // 下标i 存储无序部分的第一个元素,即下标i-1 存储有序的最后一个元素.{temp = array[i];for(j=i-1; j>=left; j--) // 下标j 初始存储有序部分的最后一个元素,并在有序部分逆向滑动.{if(temp < array[j]){array[j+1] = array[j];}else{break;}}array[j+1] = temp; // who not array[j]? 因为j--执行后 才推出了循环,所以要加回去.}
}/* 打印数组数据 */
void printArray(int* array, int size)
{int i;for(i=0; i<size; i++){printf("%d ", array[i]);}printf("\n");
}

#include "p177_quick_sort.h"int main()
{ElementType array[] = {34, 8, 64, 51, 32, 21, 64, 8};ElementType array2[] = {34, 8, 64, 51, 32, 21, 64, 8};ElementType array3[] = {34, 8, 64, 51, 32, 21, 64, 8};int size=8;    // test for quicksort.printf("\ntest for quicksort towards {34, 8, 64, 51, 32, 21, 64, 8}\n");quicksort(array, 0, size-1);printArray(array, size);	// test for median3printf("\ntest for median3 towards {34, 8, 64, 51, 32, 21, 64, 8}\n");median3(array2, 0, size-1);printArray(array2, size);// test for insertionSortprintf("\ntest for insertionSort towards {34, 8, 64, 51, 32, 21, 64, 8}\n");insertionSort(array3, 0, size-1);printArray(array3, size);
}


【2】review 插入排序代码实现(注意我的输入参数,可能和他家的不一样)

1)参数分析:这个插入排序的源码荔枝 比较灵活,因为输入参数可变,不一定非得认为 left==0,还可以对其子数组进行插入排序;

// 插入排序
void insertionSort(ElementType* array, int left, int right)
{int i, j;ElementType temp;	for(i=left+1; i<=right; i++) // 下标i 存储无序部分的第一个元素,即下标i-1 存储有序的最后一个元素.{temp = array[i];for(j=i-1; j>=left; j--) // 下标j 初始存储有序部分的最后一个元素,并在有序部分逆向滑动.{if(temp < array[j]){array[j+1] = array[j];}else{break;}}array[j+1] = temp; // who not array[j]? 因为j--执行后 才推出了循环,所以要加回去.}
}


【3】快速选择算法

1)intro:快速选择算法是从n个数中选择第k个最大(小)数算法,且是快速排序的变体算法,因为快速排序基于递归的分治算法,每轮递归后,都可以确定枢纽元的最终下标位置;所以通过 k 次 快速排序就可以确定 第k 个 最大(小)元素了,而不用对所有 元素进行排序;

2)当元素个数小于10(官方建议取10,不过这里的测试用例取3)的时候:快速排序依然会用到插入排序;

3)快速选择算法分析:快速选择算法 是 快速排序的变体算法,基本的idea是一样的,只不过 快速选择函数 多带了一个输入参数 k值,且在函数末尾要比较 i(因为 array[i] 存储着枢纽值) 和 k的大小以此来确定 该在哪个 数组范围内递归进行快速选择,代码如下:

#include <stdio.h>
#include <malloc.h>#define ElementType int
#define Error(str) printf("\nerror: %s", str)void swap(ElementType* a, ElementType* b);
ElementType median3(ElementType* array, int left, int right);
void quickselect(ElementType* array, int left, int right, int k);
void printArray(ElementType* array, int N);
void insertionSort(ElementType* array, int left, int right);// swap array arraynd b.
void swap(ElementType* array, ElementType* b)
{ElementType t;t=*array;*array=*b;*b=t;
}// 3数中值分割法 选出 left center right 分别存储最小,中间,最大值
// 然后 将中位数隐藏到倒数第2个元素 
ElementType median3(ElementType* array, int left, int right)
{	int center = (left+right)/2;if(array[left]>array[center]){swap(&array[left], &array[center]);	}if(array[left]>array[right]){swap(&array[left], &array[right]);	}if(array[center]>array[right]){swap(&array[center], &array[right]);	}/* 将中位数隐藏到倒数第2个元素 */swap(&array[center], &array[right-1]);return array[right-1];
}/* 快速选择(第k+1个最大元素), 所以如果要选择第k个最大元素,main函数需要传入k-1 */
void quickselect(ElementType array[], int left, int right, int k)
{int i, j;ElementType pivot; // 枢轴.if(k>right){Error("failed quickselect() for k is greater than right.");return;}// if(right-left >= 10) { also you can let lower limit be 10.if(right-left >= 3) { /* rihgt-left>=3,才有三数中值分割法的应用 *//* 三数分割 median3 把最大元放入array[right]了,枢纽元放入array[right-1],最小元放入array[left] */pivot = median3(array, left, right);    i = left; //i 指向最小元.j = right-1; // j 指向枢纽元.for(;;) {while(array[++i] < pivot);    /* (这里必须++i, 不能i++)找大元素,i停在那里,i起始从 left+1 */while(array[--j] > pivot);    /* (这里必须--j, 不能j--)找小元素,j停在那里,j起始从 right-2 */if(i<j){swap(&array[i], &array[j]);    /* 分割结束 */}else{break;}}//key: array[i]最后指向大元素,array[right-1]指向枢纽元,将它们交换;		swap(&array[i], &array[right-1]);  // 交换后, array[i]=枢纽元, 前面的元素小于它, 后面的元素大于它.// 上面的代码和快速排序一样,下面的代码用于基于递归的快速选择if(k > i) {quickselect(array, i+1, right, k);	}else if(k < i){quickselect(array, left, i-1, k);	}// else k == i, bingo.		                } else	/* 当数组长度小于3(10)的话,那么就采用插入排序,因为这样效率高些*/{insertionSort(array, left, right);}
}// 插入排序
void insertionSort(ElementType* array, int left, int right)
{int i, j;ElementType temp;	for(i=left+1; i<=right; i++) // 下标i 存储无序部分的第一个元素,即下标i-1 存储有序的最后一个元素.{temp = array[i];for(j=i-1; j>=left; j--) // 下标j 初始存储有序部分的最后一个元素,并在有序部分逆向滑动.{if(temp < array[j]){array[j+1] = array[j];}else{break;}}array[j+1] = temp; // who not array[j]? 因为j--执行后 才推出了循环,所以要加回去.}
}/* 打印数组数据 */
void printArray(int* array, int size)
{int i;for(i=0; i<size; i++){printf("%d ", array[i]);}printf("\n");
}
#include "p185_quick_select.h"int main()
{ElementType array[] = {34, 8, 64, 51, 32, 21, 64, 8,35, 9, 65, 50, 31, 20, 63, 8};		 int size=16;    int k = 6;// test for quickselect.printf("\ntest for quickselect towards {34, 8, 64, 51, 32, 21, 64, 8, 35, 9, 65, 50, 31, 20, 63, 8}\n");quickselect(array, 0, size-1, k-1); // pass k-1 not k, you know it.printf("\nthe %dth maximum element is %d \n", k, array[k-1]);
}



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/330977.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring boot web(2):web综合开发

1 web开发 Spring boot web 开发非常简单&#xff0c;其中包括常用的 json输出、filters、property、log等 1.1 json接口开发 在以前的Spring 开发我么提供json 的做法&#xff1a; 添加jackjson 等相关jar包配置Spring controller扫描对接的方法添加ResponseBody 而在Spri…

10道腾讯的Java面试题

转载自 10道腾讯的Java面试题 下面总结10道面试腾讯的Java面试题。 1、说几种常见的攻击方式及预防手段。 2、http1.x和http2.x的区别。 3、mysql查询语句怎么做性能分析。 4、你知道哪几种排序算法&#xff1f; 5、HashMap和HashTable的区别&#xff0c;并说明其底层实现数据…

ReviewForJob——桶式排序+基数排序(==多次桶式排序)

【0】README 1&#xff09;本文旨在 给出 ReviewForJob——桶式排序基数排序&#xff08;多次桶式排序&#xff09; 的 代码实现和代码分析&#xff1b; 2&#xff09;桶式排序基础参见 http://blog.csdn.net/pacosonswjtu/article/details/49685749&#xff0c; 基数排序基…

Spring boot(3):Spring boot中Redis 的使用

Spring boot除了常用的数据库支持外&#xff0c;对nosql数据库也进行了封装自动化。 1 Redis介绍 Redis 是目前业界使用最广泛的内存数据存储。相比memcached&#xff0c; &#xff08;1&#xff09;Redis支持更丰富的数据结构&#xff0c;例如hashes&#xff0c;lists&#x…

Java List面试题汇总

转载自 Java List面试题汇总 1、你知道的List都有哪些&#xff1f; 2、List和Vector有什么区别&#xff1f; 3、List是有序的吗&#xff1f; 4、ArrayList和LinkedList的区别&#xff1f;分别用在什么场景&#xff1f; 5、ArrayList和LinkedList的底层数据结构是什么&#…

ReviewForJob——拓扑排序+最短路径算法(有权+无权)

【0】README 1&#xff09;本文旨在给出 拓扑排序最短路径算法&#xff08;有权无权&#xff09; 的源码实现 和 分析&#xff0c;内容涉及到 邻接表&#xff0c; 拓扑排序&#xff0c; 循环队列&#xff0c;无权最短路径&#xff08;广度优先搜索&#xff09;&#xff0c;有权…

Spring boot (5):Spring data jpa 的使用

总结&#xff1a; jpa是什么&#xff0c;spring data jpa是什么&#xff1f; jpa是一套规范&#xff0c;不是一套产品。jpa是一套规范&#xff0c;不是一套产品。 spring data jpa是spring基于ORM框架、JPA规范的基础上封装的一套JPA应用框架&#xff0c;提供了包括增删改等在…

Java Map集合面试题汇总

转载自 Java Map集合面试题汇总1、 你都知道哪些常用的Map集合?2、Collection集合接口和Map接口有什么关系&#xff1f;3、HashMap是线程安全的吗&#xff1f;线程安全的Map都有哪些&#xff1f;性能最好的是哪个&#xff1f;4、使用HashMap有什么性能问题吗&#xff1f;5、Ha…

ReviewForJob——二叉堆优先队列的实现(三种堆节点类型——int + struct HeapNode + struct HeapNode*)

【0】README 1&#xff09;本文旨在给出 二叉堆优先队列的实现 的代码实现和分析&#xff0c; 而堆节点类型 不外乎三种&#xff1a; 一&#xff0c; 基本类型如int&#xff1b; 二&#xff0c;结构体类型 struct HeapNode&#xff1b; 三&#xff0c;结构体指针类型 struct H…

Spring boot(六):如何优雅的使用mybatis

总结 hibernate 和 mybatis 的区别 hibernate的特点是所有的sql都用java代码生成&#xff0c;不用跳出程序去&#xff08;看&#xff09;sql&#xff0c;发展到最顶端就是Spring data jpa了。 mybatis初期使用比较麻烦&#xff0c;需要各种配置文件、实体类、dao层映射关联、还…

Java中创建String的两道面试题及详解

转载自 Java中创建String的两道面试题及详解 我们知道创建一个String类型的变量一般有以下两种方法&#xff1a; String str1 "abcd";String str2 new String("abcd"); 那么为什么会存在这两种创建方式呢&#xff0c;它们在内存中的表现形式各有什么区别…

ReviewForJob——最小生成树(prim + kruskal)源码实现和分析

【0】README 1&#xff09;本文旨在给出 ReviewForJob——最小生成树&#xff08;prim kruskal&#xff09;源码实现和分析&#xff0c; 还会对其用到的 技术 做介绍&#xff1b; 2&#xff09;最小生成树是对无向图而言的&#xff1a;一个无向图G 的最小生成树是一个连通图…

Spring boot(七):Spring boot+ mybatis 多数据源最简解决方案

多数据源一般解决哪些问题&#xff1f;主从模式或者业务比较复杂需要连接不同的分库来支持业务。 直接上代码。 配置文件 pom包依赖&#xff0c;该依赖的依赖。主要是数据库这边的配置&#xff1a; mybatis.config-locationsclasspath:mybatis/mybatis-config.xmlspring.da…

Java:关于main方法的10道面试题

转载自 Java&#xff1a;关于main方法的10道面试题 1.main方法是做什么用的&#xff1f; 2.不用main方法如何运行一个类&#xff1f; 3.main方法如何传递参数&#xff1f;传递参数的类型是什么&#xff1f;能不能改变该参数类型&#xff1f; 4.main方法为什么是静态的&#xff…

ReviewForJob——深度优先搜索的应用

【0】README 1&#xff09;本文旨在 介绍 ReviewForJob——深度优先搜索的应用 及其 源码实现 &#xff1b; 2&#xff09;搜索树的技术分为广度优先搜索 和 深度优先搜索&#xff1a;而广度优先搜索&#xff0c;我们前面利用 广度优先搜索计算无权最短路径已经做过分析了&am…

Spring boot(八):RabbitMQ详解

RabbitMQ介绍 RabbitMQ既一个消息队列&#xff0c;主要用来实现应用程序的异步和解耦&#xff0c;同时也能起到消息缓冲&#xff0c;消息分发的作用。 消息中间件在互联网公司的使用中越来越多。消息中间件最主要的作用是解耦&#xff0c;中间件最标准的用法师生产者生产消息传…

关于Jvm知识看这一篇就够了

转载自 关于Jvm知识看这一篇就够了2016年左右的时候读了周志明《深入理解Java虚拟机&#xff1a;JVM高级特性与最佳实践》&#xff0c;读完之后受益匪浅&#xff0c;让我对Java虚拟机有了一个完整的认识&#xff0c;这是Jvm书籍中最好的读物之一。后来结合实际工作中遇到的问题…

ReviewForJob——算法设计技巧(贪婪算法+分治算法+动态规划)

【0】README 1&#xff09;本文旨在介绍算法设计技巧包括 贪婪算法、分治算法、动态规划 以及相关的荔枝等&#xff1b; 【1】贪婪算法 1&#xff09;intro&#xff1a; 贪婪算法是分阶段进行的&#xff0c;在每个阶段&#xff0c;可以认为所做的决定是最好的&#xff0c;而…

Spring boot(九):定时任务

在我们的项目开发过程中&#xff0c;进场需要定时任务来帮助我们做一些内容&#xff0c;springboot默认已经帮我们实行了&#xff0c;只要天剑相应的注解就可以实现。 1、pom包配置 pom包里面只需要引入springboot starter包即可 <dependencies><dependency><…

jvm系列(一):java类的加载机制

转载自 jvm系列(一):java类的加载机制1、什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中&#xff0c;将其放在运行时数据区的方法区内&#xff0c;然后在堆区创建一个 java.lang.Class对象&#xff0c;用来封装类在方法区内的数据结构。类的加载的最…