本篇博客实现了 1.冒泡排序 2.冒泡排序的一种优化(当某次冒泡没有进行交换时,退出循环) 3.选择排序 4.归并排序 5.快速排序。

主要是源码的实现,并将自己在敲的过程中所遇到的一些问题记录下来。

全局定义与相关声明:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; int num[100005]; //存储数组 void swap1(int i, int j) //交换函数swap
{
int t = num[i];
num[i] = num[j];
num[j] = t;
} /*Printnum 输出*/ void Printnum(int n) //输出排序完成的数组
{
for (int i = 1; i <= n; i++) {
cout << num[i] << " ";
} cout << endl;
}

1.冒泡排序

/*Bubble_Sort 冒泡排序*/

void Bubble_Sort(int n)
{
int i, j; for (i = 1; i <= n; i++) //遍历n次
{
for (j = 1; j <= n-i; j++) //每次都把最大数往后排,缩小范围
{
if (num[j] > num[j+1])
{
swap1(j, j+1);
}
}
}
}

冒泡的思想:不断把范围中的最大数往后排,排完之后缩小范围;以上过程执行n次。

个人小结:思想很简单,但是太久不碰真的会忘记。

2.冒泡排序的优化

void Bubble_Sort_Better(int n)
{
int i, j; for (i = 1; i <= n; i++)
{
bool flag = true; for (j = 1; j <= n-i; j++)
{
if (num[j] > num[j+1])
{
flag = false; swap1(j, j+1);
}
} if (flag) break; //某一次遍历没有发生交换时,结束
}
}

优化的思想:当某一次冒泡没有交换任何数时,则说明当前范围内序列有序,结束循环。

3.选择排序

/*Selection_Sort 选择排序*/

void Selection_Sort(int n)
{
int i, j; int rcd; for (i = 1; i <= n; i++)
{
rcd = i; for (j = i+1; j <= n; j++)
{
if (num[j] < num[rcd]) //找出i+1=>n范围内的最小元并前移
{
rcd = j;
}
} swap1(i, rcd);
}
}

思想:找出范围i => n内最小的数,用rcd(初始化为i)记录其位置,之后与寻找范围内的第一个数num[i]进行交换,保证i+1 => n的所有数均大于num[i]。

4.归并排序:

/*Merge_Sort 归并排序*/

int temp[100005];

void Merge_Array(int l1, int r1, int l2, int r2)
{
int p1 = l1;
int p2 = l2; int i = 1; memset(temp, 0, sizeof(temp)); for (i = l1; i <= r2; i++)
{
if (p1 > r1)
{
temp[i] = num[p2++]; continue;
} if (p2 > r2)
{
temp[i] = num[p1++]; continue;
} if (num[p1] < num[p2])
{
temp[i] = num[p1++]; continue;
} else
{
temp[i] = num[p2++]; continue;
}
} for (i = l1; i <= r2; i++)
{
num[i] = temp[i];
} } void Merge_Sort(int l, int r)
{
if (l < r)
{
int mid = (l+r)/2; Merge_Sort(l, mid); //l => mid
Merge_Sort(mid+1, r); //mid+1 => r Merge_Array(l, mid, mid+1, r); //l => mid => mid+1 => r
}
}

思想可以参考:白话经典算法系列之五 归并排序的实现

大概的思路是,先并后归,将范围二分,分别递归排序之后再进行合并(利用一个额外的数组temp)。

个人小结:

1.看似简单,实现起来总是会出问题;动手吧。

2.一定要注意:递归选取的范围,取了mid = (l+r)/2之后,左边的一半范围为[l => mid],右边的一半范围为[mid+1 => r]。原因可以考虑以下情况:两个数3 1进行排序,mid = 1,如果选取的范围为[l => mid-1]和[mid => r](这里是[1 => 1]和[1 => 2]),则会出现死循环。

5.QuickSort快速排序

int Quick_Sort_Adjust(int l, int r)
{
int key = l; //选取第一个元素为基准值 int a, b; a = l+1; b = r; while (a < b)
{
bool out_bound = false; while (1)
{
if (num[a] > num[key]) break; a++; if (a > r)
{
out_bound = true; break;
}
} while (1)
{
if (num[b] < num[key]) break; b--; if (b < l)
{
out_bound = true; break;
}
} if (out_bound || a >= b) break; //如果出现越界或a>=b直接结束 swap1(a, b); a++;
b--;
} swap1(key, a-1); return a-1;
} void Quick_Sort(int l, int r)
{
if (l < r)
{
int mid = Quick_Sort_Adjust(l, r); Quick_Sort(l, mid-1); //l => mid-1
Quick_Sort(mid+1, r); //mid+1 => r
}
}

思想可以参考:白话经典算法系列之六 快速排序 快速搞定

思路上文讲的很清楚了,建议在纸上模拟以下四种情况:

1.n = 7
1 3 1 2 -1 8 9 2.n = 7
1 1 1 1 1 1 1 3.n = 7
7 6 5 4 3 2 1 4.n = 7
7 1 1 1 1 1 1

个人小结:

1.同样的,自己敲一遍能够发现一堆问题。

2.一定要注意,当出现以下两种情况时:(1)i>j(这里的代码是a>b) (2)i、j越界 应该立即退出循环。

3.递归范围的选择,在基准值num[key]和num[mid]交换之后,接下来的递归范围应该为[l => mid-1]和[mid+1 => r],因为[l => mid-1]范围内的所有值都小于num[mid],[mid+1 => r]内的所有值都大于num[mid];如果选取范围对mid取等,会出现上文中两个数(如 3 1)的死循环。

4.这里选择的基准是第一个数,快速排序还有很多改进版本,如随机选择基准数,区间内数据较少时直接用别的方法排序以减小递归深度。

完整代码如下:

//
// main.cpp
// Sort
//
// Created by wasdns on 16/12/25.
// Copyright © 2016年 wasdns. All rights reserved.
// #include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; /*存储数组定义*/ int num[100005]; void swap1(int i, int j)
{
int t = num[i];
num[i] = num[j];
num[j] = t;
} /*Printnum 输出*/ void Printnum(int n)
{
for (int i = 1; i <= n; i++) {
cout << num[i] << " ";
} cout << endl;
} /*Bubble_Sort 冒泡排序*/ void Bubble_Sort(int n)
{
int i, j; for (i = 1; i <= n; i++) //遍历n次
{
for (j = 1; j <= n-i; j++) //每次都把最大数往后排,缩小范围
{
if (num[j] > num[j+1])
{
swap1(j, j+1);
}
}
}
} void Bubble_Sort_Better(int n)
{
int i, j; for (i = 1; i <= n; i++)
{
bool flag = true; for (j = 1; j <= n-i; j++)
{
if (num[j] > num[j+1])
{
flag = false; swap1(j, j+1);
}
} if (flag) break; //某一次遍历没有发生交换时,结束
}
} /*Selection_Sort 选择排序*/ void Selection_Sort(int n)
{
int i, j; int rcd; for (i = 1; i <= n; i++)
{
rcd = i; for (j = i+1; j <= n; j++)
{
if (num[j] < num[rcd]) //找出i+1=>n范围内的最小元并前移
{
rcd = j;
}
} swap1(i, rcd);
}
} /*Merge_Sort 归并排序*/ int temp[100005]; void Merge_Array(int l1, int r1, int l2, int r2)
{
int p1 = l1;
int p2 = l2; int i = 1; memset(temp, 0, sizeof(temp)); for (i = l1; i <= r2; i++)
{
if (p1 > r1)
{
temp[i] = num[p2++]; continue;
} if (p2 > r2)
{
temp[i] = num[p1++]; continue;
} if (num[p1] < num[p2])
{
temp[i] = num[p1++]; continue;
} else
{
temp[i] = num[p2++]; continue;
}
} for (i = l1; i <= r2; i++)
{
num[i] = temp[i];
} } void Merge_Sort(int l, int r)
{
if (l < r)
{
int mid = (l+r)/2; Merge_Sort(l, mid); //l => mid
Merge_Sort(mid+1, r); //mid+1 => r Merge_Array(l, mid, mid+1, r); //l => mid => mid+1 => r
}
} /*Quick_Sort 快速排序*/ int Quick_Sort_Adjust(int l, int r)
{
int key = l; //选取第一个元素为基准值 int a, b; a = l+1; b = r; while (a < b)
{
bool out_bound = false; while (1)
{
if (num[a] > num[key]) break; a++; if (a > r)
{
out_bound = true; break;
}
} while (1)
{
if (num[b] < num[key]) break; b--; if (b < l)
{
out_bound = true; break;
}
} if (out_bound || a >= b) break; //如果出现越界或a>=b直接结束 swap1(a, b); a++;
b--;
} swap1(key, a-1); return a-1;
} void Quick_Sort(int l, int r)
{
if (l < r)
{
int mid = Quick_Sort_Adjust(l, r); Quick_Sort(l, mid-1); //l => mid-1
Quick_Sort(mid+1, r); //mid+1 => r
}
} int main()
{
int n; cin >> n; for (int i = 1; i <= n; i++)
{
cin >> num[i];
} int option; cin >> option; if (option == 1)
{
cout << "Bubble_Sort" << endl; Bubble_Sort(n);
} else if (option == 2)
{
cout << "Bubble_Sort_Better" << endl; Bubble_Sort_Better(n);
} else if (option == 3)
{
cout << "Selection_Sort" << endl; Selection_Sort(n);
} else if (option == 4)
{
cout << "Merge_Sort" << endl; Merge_Sort(1, n);
} else if (option == 5)
{
cout << "Quick_Sort" << endl; Quick_Sort(1, n);
} Printnum(n); return 0;
}

2016/12/26

DataStructure 排序 源码实现的更多相关文章

  1. html5 Sortable.js 拖拽排序源码分析

    最近公司项目经常用到一个拖拽 Sortable.js插件,所以有空的时候看了 Sortable.js 源码,总共1300多行这样,写的挺完美的.   本帖属于原创,转载请出名出处. 官网http:// ...

  2. 解读 v8 排序源码

    前言 v8 是 Chrome 的 JavaScript 引擎,其中关于数组的排序完全采用了 JavaScript 实现. 排序采用的算法跟数组的长度有关,当数组长度小于等于 10 时,采用插入排序,大 ...

  3. C#冒泡法排序源码

    如下内容内容是关于C#冒泡法排序的内容,应该对码农有一些用途. int[] myArray = new int[] { 10, 8, 3, 5, 6, 7, 4, 6, 9 }; for( int j ...

  4. springboot源码解析-管中窥豹系列之排序(五)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  5. spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

    更多文章点击--spring源码分析系列 主要分析内容: 一.BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor简述与demo示例 ...

  6. laravel源码解析

    本专栏系列文章已经收录到 GitBooklaravel源码解析 Laravel Passport——OAuth2 API 认证系统源码解析(下)laravel源码解析 Laravel Passport ...

  7. [Guava源码分析]Ordering:排序

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3876466.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  8. 三种排序算法python源码——冒泡排序、插入排序、选择排序

    最近在学习python,用python实现几个简单的排序算法,一方面巩固一下数据结构的知识,另一方面加深一下python的简单语法. 冒泡排序算法的思路是对任意两个相邻的数据进行比较,每次将最小和最大 ...

  9. Solr4.8.0源码分析(6)之非排序查询

    Solr4.8.0源码分析(6)之非排序查询 上篇文章简单介绍了Solr的查询流程,本文开始将详细介绍下查询的细节.查询主要分为排序查询和非排序查询,由于两者走的是两个分支,所以本文先介绍下非排序的查 ...

随机推荐

  1. 【Eclipse】总结自己在工作中经常使用到的Eclipse快捷键

    一些我觉得比较有用的快捷键,仅作参考. 1.alt + shift + c :更改方法签名. 2.三次鼠标左键单击: 选中一整行. 3.alt + shift + d/x: 再按t : 运行junit ...

  2. windows7 启用管理员账户

    在虚拟机中安装了windows7,方便使用qq,使用百度云,office等常用的软件.虚拟机使用的oracle的VirtualBox,个人使用体验不错,最棒的功能是能将物理机中的磁盘映射到虚拟机中网络 ...

  3. .NET LINQ查询操作中的类型关系

    LINQ 查询操作中的类型关系      若要有效编写查询,您应该了解完整的查询操作中的变量类型是如何全部彼此关联的. 如果您了解这些关系,就能够更容易地理解文档中的 LINQ 示例和代码示例. 另外 ...

  4. AngularJS的JSONP服务

    有些页面的response中,包含了 Access-Control-Allow-Origin 这个header,说明可以进行跨域请求,如果没有包含这个header的页面可以利用JSONP进行跨域 sc ...

  5. Memcache之内存分配机制

    可参见:http://blog.csdn.net/hguisu/article/details/7353482

  6. @Html.Partial和@Html.Action区别

    1.首先看一下它们的对等关系 @Html.Partial 对应 @{Html.RenderPartial();}@Html.Action 对应 @{Html.RenderAction();} 以上相互 ...

  7. python多线程编程

    Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...

  8. 通过VS创建简单的WCF服务

    http://www.cnblogs.com/artech/archive/2007/09/15/893838.html http://www.topwcftutorials.net/2013/09/ ...

  9. Linux服务器init 5启动图形界面,报错Retrigger failed udev events的解决方法

    1.开启linux系统的桌面环境,使用startx未成功,报如下错误: 提示:Retrigger failed udev events [root@ /]# startx xauth: creatin ...

  10. Discuz!用户注册,登陆,生成帖子功能实现

    <?php /* * Disucz!部分功能使用说明: */ /***************************************************************** ...