几种常用排序算法和图论
来源:互联网 发布:宋代权知开封府事 编辑:程序博客网 时间:2024/06/01 11:23
这段时间在学算法,总结一下几种常用的排序算法
1,冒泡排序算法
此算法算是入门排序算法,
public void sort(int[] a)
{
int temp = 0;
for (int i = a.length - 1; i > 0; --i)
{
for (int j = 0; j < i; ++j)
{
if (a[j + 1] < a[j])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
2,快速排序
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序(百度词条)此算法是分治法和递归的完美使用,算法中使用了递归,不适合大数据量排序
public static void quickSort(int[] array,int begin,int end){
if(end-begin<=1) {return ;}
int x=array[begin];//31
int low=begin;//0
int high=end;//5
//由于会在两头取数据,需要一个方向
boolean direction =true;
//开始进行数据的移动
L1:
while(low<high){
if(direction){//从右往左找
for(int i=high;i>low;i--){
if(array[i]<=x){
array[low++]=array[i];
high=i;
direction=!direction;
continue L1;
}
}
high=low;
}else{
for(int i=low;i<high;i++){
if(array[i]>=x){
array[high--]=array[i];
low=i;
direction=!direction;
continue L1;
}
}
low=high;
}
}
//把最后找到的值放入中间位置
array[low]=x;
//开始完成左右两边的操作
quickSort(array,begin,low-1);//L
quickSort(array,low+1,end);//R
}
3,基数排序
它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
举例子,对扑克牌的排序,要按花色和点数排序。那么基数排序就是先拿点数1-13分为13组,不同的点数放在不同的组,然后把这13组首位相连再
按花色排序,这样拍出来就是按点数和花色排好序的了(按不同的维度进行排序),适用于类别较明显的场景,如扑克牌,麻将等。
以麻将排序为例:
public static void radixSort(LinkedList<Mahjong> list){
//先对点数进行分组
LinkedList[] rankList=new LinkedList[9];
for (int i=0;i<rankList.length;i++){
rankList[i]=new LinkedList();
}
//把数据一个一个的放入到对应的组中
while(list.size()>0){
//取一个
Mahjong m=list.remove();
//放到组中
rankList[m.rank-1].add(m);
}
//把9个组合到一起
for (int i = 0; i < rankList.length; i++) {
list.addAll(rankList[i]);
}
//先花色数进行分组
LinkedList[] suitList=new LinkedList[3];
for (int i=0;i<suitList.length;i++){
suitList[i]=new LinkedList();
}
//把数据一个一个的放入到对应的组中
while(list.size()>0){
//取一个
Mahjong m=list.remove();
//放到组中
suitList[m.suit-1].add(m);
}
//把3个组合到一起
for (int i = 0; i < suitList.length; i++) {
list.addAll(suitList[i]);
}
}
4,插入排序
输入一个元素,检查数组列表中的每个元素,将其插入到一个已经排好序的数列中的适当位置,使数列依然有序,当最后一个元素放入合适位置时,该数组排序完毕。其实质就是比较,交换位置。对于已经大部分有序的队列效率较高:
public void insertSort(int[] array){
for(int i=1;i<array.length;i++){
int j=i;
int target=array[i];//表示想插入的数据
while(j>0 && target<array[j-1]){//如果插入的数据小于数组的前一个时
array[j]=array[j-1];
j--;
}
array[j]=target;
}
}
5,希尔排序
希尔排序法(缩小增量法) 属于插入类排序,是将整个无序列分割成若干小的子序列分别进行插入排序的方法。是对插入排序的升级,解决插入排序
交换过多造成的性能消耗,适合大数据量排序(当然小数据两也没问题,步长 : (1,4,10,23,57,132,301,701,1750,…))
public static void shellSort(int[] array,int step){
//3 9 1 2 5 4 7 8 6
//2 5 1 3 8 4 7 9 6
for(int k=0;k<step;k++) {//对步长的定位,选择每次操作的开始位置
for(int i=k+step;i<array.length;i=i+step){//i表示从第2个数开始插入
int j=i;
int target=array[i];//表示想插入的数据
while(j>step-1 && target<array[j-step]){//如果插入的数据小于数组的前一个时
array[j]=array[j-step];
j=j-step;
}
array[j]=target;
}
}
}
6.堆排序
堆排序(号称大数据中使用最快的查找算法,哈哈没有做过深入研究) 一棵完全二叉树,如果某个节点的值总是不小于其父节点的值,则根节点的关键字是所有节点关键字中最小的,称为小根堆(小顶堆);如果某个节点的值总是不大于 其父节点的值,则根节点的关键字是所有节点关键字中最大的,称为大根堆(大顶堆)。 初始时把要排序的n个数看作是一棵顺序存储的完全二叉树,调整它们的存储顺序,使之 成为一个堆,将堆顶元素输出,得到n 个元素中最小(最大)的元素,这时堆的根节点的 数最小(或者最大)。然后对前面(n-1)个元素重新调整使之成为堆,输出堆顶元素,得 到n 个元素中次小(或次大)的元素。依次类推,直到只有两个节点的堆,并对它们作交 换,最后得到有n个节点的有序序列。这个过程就称为堆排序。 参考:http://blog.csdn.net/u012152619/article/details/47452813
堆排序分为两步走,建堆和排序
public void sortHeap() { int[] array = {12, 15, 25, 20, 14, 16, 50, 35, 30}; createHeap(array); System.out.println("建堆完成:"); printArray(array); int last = array.length - 1; System.out.println("排序打印"); while (last >= 0) { System.out.print(array[0] + " "); swap(array, 0, last); last--; sortHeap(array, 0, last); }}private void createHeap(int[] array) { for (int i = (array.length - 1) / 2; i >= 0; i--) { sortHeap(array, i, array.length); }}/** * 调整数据以建成堆 * * @param array * @param sortIndex * @param lastIndex */private void sortHeap(int[] array, int sortIndex, int lastIndex) { int leftChildIndex = 2 * sortIndex + 1; int rightChildIndex = 2 * sortIndex + 2; int smallerIndex = sortIndex; if (leftChildIndex < lastIndex && array[leftChildIndex] < array[smallerIndex]) { smallerIndex = leftChildIndex; } if (rightChildIndex < lastIndex && array[rightChildIndex] < array[smallerIndex]) { smallerIndex = rightChildIndex; } if (smallerIndex != sortIndex) { swap(array, sortIndex, smallerIndex); sortHeap(array, smallerIndex, lastIndex); }}private void swap(int[] array, int sortIndex, int smallerIndex) { int temp = array[sortIndex]; array[sortIndex] = array[smallerIndex]; array[smallerIndex] = temp;}
7,图论----最小生成树 prim算法MST(Minimum Spanning Tree,最小生成树)问题有两种通用的解法,Prim算法就是其中之一,它是从点的方面考虑构建一颗MST,大致思想是:设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗MST。(网上的定义)
由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。
所以最小生成树的作用就是找到连通图中连接各个顶点最小的路径。城市间网络建设,高速路修建等。
public void prim() {
//当lowcost[i] == 0 时,表示节点i 已经被查找
//如果lowcost[i] != 0 ,那么必然有一个值,
//这个值可以用来表示查找到的集合(节点的连通分量)到
//下标为i 的这个节点的距离
int[] lowcost = new int[verticeSize];
for(int i = 0; i < verticeSize; i++) {
lowcost[i] = matrix[0][i];
}
//
int min;
int minId;
int sum = 0;
for(int i = 0; i < verticeSize; i++) {
min = MAX_WEIGHT;
minId = 0;
//step1: 查找剩下的节点到已经被查找节点集合U中最短的边的节点
for(int j = 1; j < verticeSize; j++) {
if (lowcost[j] < min && lowcost[j] > 0) {
min = lowcost[j];
minId = j;
}
}
if (min == MAX_WEIGHT) {
break;
}
sum +=min;
//step2:找到这个节点后,我要更新剩下来的节点到已经被查找节点集合U 的距离
lowcost[minId] = 0;
for(int j = 1; j < verticeSize; j++) {
if (lowcost[j] != 0 && matrix[minId][j] < lowcost[j]) {
lowcost[j] = matrix[minId][j];
}
}
}
System.out.println("最小生成树代价:" + sum);
}
8,图论--------Dijkstra算法
Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。该算法用于最短路径查找
1)算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。
2)算法步骤:
a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。
b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。
c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
d.重复步骤b和c直到所有顶点都包含在S中。
public Dijkstra(Graph g, int sourcePoint) {graph = g;
sourceP= sourcePoint;
verticeS = new int[graph.verticeSize];
distance = new int[graph.verticeSize];
edge = graph.matrix;
calculate();
display();
}
private void display() {
for(int i = 0; i < graph.verticeSize; i++) {
System.out.println(i + ": " + distance[i]);
}
}
private void calculate() {
int minDis;
int u = 0;
// 初始化
for(int i = 0; i < graph.verticeSize; i++) {
distance[i] = edge[sourceP][i];
verticeS[i] = 0;
}
verticeS[sourceP] = 1;
//轮询
for(int i = 1; i < graph.verticeSize; i++) {
minDis = graph.MAX_WEIGHT;
// 1.查找最短的那条边
// 将找到的边对应的节点保存到u
for(int j = 0; j < graph.verticeSize; j++) {
if (verticeS[j] == 0 && distance[j] < minDis) {
u = j;
minDis = distance[j];
}
}
//说明已经找完了
if (minDis == graph.MAX_WEIGHT) {
return;
}
verticeS[u] = 1;
//2. 更新distance,也就是起始点到其他未访问节点的距离
for(int j = 0; j < graph.verticeSize; j++) {
if (verticeS[j] == 0 && edge[u][j] < Graph.MAX_WEIGHT) {
if (distance[u] + edge[u][j] < distance[j]) {
distance[j] = distance[u] + edge[u][j];
}
}
}
}
}
- 几种常用排序算法和图论
- 几种常用排序算法
- 几种常用排序算法
- 几种常用排序算法
- 几种常用排序算法
- 几种常用的查找和排序算法
- 常用的几种排序算法详解和实现
- 几种常用排序算法的思路和复杂度对比
- 【算法】几种常用排序算法
- 几种常用的基本排序算法
- C#几种常用的排序算法
- C#几种常用的排序算法
- C#几种常用的排序算法:
- 几种常用的排序算法
- C#几种常用的排序算法
- 几种常用排序算法总结
- 几种常用排序算法总结
- 几种常用排序算法总结(转载)
- JAVA 代码块 继承
- tcp/ip学习笔记--第29章 NFS network file system
- JAVA 代码块 继承 final
- node,起航
- spring-web和spring-webmvc 版本冲突jar包冲突
- 几种常用排序算法和图论
- Python中理解进程(Process),线程(Thread)和协程(Coroutines)的感悟
- sql语句备份还原数据库
- SQL小结 增删改查 创建数据库 建表
- MIMXRT1050-EVK开发板在IAR环境下的下载问题
- 实测 CORS 跨域访问之 Access-Control-Allow-Origin 多域名设置
- 你可能不需要vuex
- redis学习笔记五(持久化)
- 深度学习系列笔记之线性代数