冒泡排序、归并排序、快速排序、堆排序
2015-08-30 22:03
627 查看
冒泡排序
首先比较第1个和第2个数的大小,根据结果决定互换两数的值或保持不变,接着比较第2个和第3个数的大小,根据结果决定互换两数的值或保持不变,依次类推,不断循环直至排序完成。#include "stdafx.h" #include <iostream> using namespace std; void maopao(char *); void swap(char *a,char *b); int _tmain(int argc, _TCHAR* argv[]) { char a[100]; gets(a); maopao(a); cout <<a<<endl; return 0; } void maopao(char *x) { int i; int snap=true; int len; len=strlen(x); while(snap) { snap=false; for(i=0;i<=len-2;i++) { if(x[i]>x[i+1]) { swap(&x[i],&x[i+1]); snap=true; } } } } void swap(char *a,char *b) { char i; i=*a; *a=*b; *b=i; }
归并排序
首先将数组从中间分为两组,左边一组的个数和右边一组的个数相等或者比右边一组多一个,利用递归将左边一组和右边一组的数据分别排好序,然后合并两组数据。这种排序方法需要设置一个大小与原数组一样的数组作为辅助数组。#include "stdafx.h" #include<iostream> using namespace std; void guibing(int *,int,int,int *); void guibing_all(int *,int,int,int,int *); #define sum 4 int _tmain(int argc, _TCHAR* argv[]) { int a[sum]; int b[sum]; int i; for(i=0;i<sum;i++) { cin>>a[i]; } guibing(a,0,sum-1,b); for(i=0;i<sum;i++) { cout<<a[i]<<endl; } return 0; } void guibing(int *a,int low,int high,int *b) { if(low<high) { int mid; mid=(low+high)/2; guibing(a,low,mid,b); guibing(a,mid+1,high,b); guibing_all(a,low,mid,high,b); } } void guibing_all(int *a,int low,int mid,int high,int *b) { int i,j,k; i=low; j=mid+1; k=low; while((i<=mid)&&(j<=high)) { if(a[i]<=a[j]) { b[k]=a[i]; i++; k++; } else { b[k]=a[j]; j++; k++; } } if((i<=mid)&&(j>high)) while(i<=mid) { b[k]=a[i]; i++; k++; } else while(j<=high) { b[k]=a[j]; j++; k++; } for(i=low;i<=high;i++) { a[i]=b[i]; } }
快速排序
方法一
选择一个支点数据,一般选用序列最左边的数作为支点数据,然后通过交换两个数的位置将小于支点数据的数据跟随在支点数据后,然后才是大于支点数据的数,通过互换位置将支点数据换到两组数据的中间,利用递归对两组数据进行排序。如对于序列{17,43,27,31,4,3,9,33,10,43,14,7},选用17作为支点数据,然后将43和4互换位置,3和27互换位置,9和31互换位置,10和43互换位置,14和27互换位置,7和31互换位置,变为{17,4,3,9,10,14,7,33,43,43,27,31},然后互换17和7的位置,变为{7,4,3,9,10,14,17,33,43,43,27,31},利用递归对17两边的序列{7,4,3,9,10,14}、{33,43,43,27,31}进行排序,最后得到{3,4,7,9,10,14,17,27,31,33,43,43}。顺序依次为:{17,43,27,31,4,3,9,33,10,43,14,7}
{17,4,27,31,43,3,9,33,10,43,14,7}
{17,4,3,31,43,27,9,33,10,43,14,7}
{17,4,3,9,43,27,31,33,10,43,14,7}
{17,4,3,9,10,27,31,33,43,43,14,7}
{17,4,3,9,10,14,31,33,43,43,27,7}
{17,4,3,9,10,14,7,33,43,43,27,31}
{7,4,3,9,10,14,17,33,43,43,27,31}
方法二
以上是一种分组的方法,下面介绍快速排序另一种分组的方法。快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。
举例说明,假设要排序的序列为2 4 9 3 6 7 1 5
2 2 4 9 3 6 7 1 5 首先用2当作基准,使用i j两个指针分别从两边进行扫描,把比2小的元素和比2大的元素分开。首先比较2和5,5比2大,j左移
2 2 4 9 3 6 7 1 5 比较2和1,1小于2,所以把1放在2的位置
2 1 4 9 3 6 7 1 5 比较2和4,4大于2,因此将4移动到后面
2 1 4 9 3 6 7 4 5 比较2和7,2和6,2和3,2和9,全部大于2,满足条件,因此不变
经过第一轮的快速排序,元素变为下面的样子
[1] 2 [9 3 6 7 4 5]
之后,在把2左边的元素进行快排,由于只有一个元素,因此快排结束。右边进行快排,递归进行,最终生成最后的结果。
一个排列结果为从小到大的例子:
#include <iostream> using namespace std; void quicksort(int *,int,int); int main() { int a[8]={8,52,24,5,3,78,34,7}; quicksort(a,0,7); int i; for(i=0;i<8;i++) { cout<<a[i]<<endl; } return 0; } void quicksort(int *v, int left, int right) { if(left < right) { int key = v[left]; int low = left; int high = right; while(low < high) { while(low < high && v[high] >= key) { high--; } v[low] = v[high]; while(low < high && v[low] <= key) { low++; } v[high] = v[low]; } v[low] = key; quicksort(v,left,low-1); quicksort(v,low+1,right); } }
若要从大到小排列,只需改变两个地方:
void quicksort(int *v, int left, int right) { if(left < right) { int key = v[left]; int low = left; int high = right; while(low < high) { while(low < high && v[high] <= key)/*改这行*/ { high--; } v[low] = v[high]; while(low < high && v[low] >= key)/*改这行*/ { low++; } v[high] = v[low]; } v[low] = key; quicksort(v,left,low-1); quicksort(v,low+1,right); } }
对于某些特殊情况,快速排序效率会比较低,如对于逆序输入,为了解决这种情况,可以不选第1个数据作为支点数据。随机快速排序就是在序列中随机选出一个数据作为支点数据,做法很简单,只需要将这个随机选出来的数据和第1个数据的位置互换即可。
堆排序
堆定义
堆的定义如下:n个元素的序列{r1, r2, …,rn},当且仅当满足以下关系时,称之为堆:将此序列对应到一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值必须小于或等于(大于或等于)其孩子结点。由此可知,若序列{r1, r2, …,rn}是堆,则堆顶元素r1必为所有元素中的最小(大)值。根据这个特性,引出了堆排序。
实现堆排序的两大步骤:
1. 将一个无序序列建成一个堆
2. 输出堆顶元素后,将剩余的元素重新调整为一个新堆,并反复执行这一步直至结束
步骤一
将一个无序序列建立成堆是一个从下往上“筛选”的过程,因为这样可以调用步骤二(调整新堆)的方法来实现。以小顶堆为例:void build_heap(int *h,int length) { int i = length/2-1; for(i;i>=0;--i) { adjust_heap(h,length,i); } }
步骤二
将堆顶元素拿出后,以堆中最后一个元素替代它,然后依次从上到下调整。void adjust_heap(int *h,int length,int key) { int left = 2*key+1; int right = 2*key+2; int middle = key; int swapped = true; while(swapped) { swapped = false; if(left >= length) break; else if(right == length) { if(h[middle]>h[left]) { int temp = h[middle]; h[middle] = h[left]; h[left] = temp; } } else { if((h[middle]<=h[left]) && (h[middle]<=h[right])) break; if(h[left]<=h[right]) { int temp = h[middle]; h[middle] = h[left]; h[left] = temp; middle = left; swapped = true; } else { int temp = h[middle]; h[middle] = h[right]; h[right] = temp; middle = right; swapped =true; } left = 2*middle+1; right = 2*middle+2; } } }
总的程序为:
#include<iostream>
using namespace std;
void build_heap(int *,int,int);
void adjust_heap(int *,int,int);
void heap_sort(int *,int);
int main()
{
int a[8]={49,38,65,97,76,13,27,50};
heap_sort(a,8);
int i;
for(i=0;i<8;i++)
cout<<a[i]<<' ';
cout<<endl;
return 0;
}
void build_heap(int *h,int length) { int i = length/2-1; for(i;i>=0;--i) { adjust_heap(h,length,i); } }
void adjust_heap(int *h,int length,int key)
{
int left = 2*key+1;
int right = 2*key+2;
int middle = key;
int swapped = true;
while(swapped)
{
swapped = false;
if(left >= length)
break;
else if(right == length)
{
if(h[middle]>h[left])
{
int temp = h[middle];
h[middle] = h[left];
h[left] = temp;
}
}
else
{
if((h[middle]<=h[left]) && (h[middle]<=h[right]))
break;
if(h[left]<=h[right])
{
int temp = h[middle];
h[middle] = h[left];
h[left] = temp;
middle = left;
swapped = true;
}
else
{
int temp = h[middle];
h[middle] = h[right];
h[right] = temp;
middle = right;
swapped =true;
}
left = 2*middle+1;
right = 2*middle+2;
}
}
}
void heap_sort(int *h,int length)
{
build_heap(h,length);
while(length>1)
{
int temp = h[0];
h[0] = h[length-1];
h[length-1] = temp;
length--;
adjust_heap(h,length,0);
}
}
相关文章推荐
- 算法篇——因子和阶乘
- javascript的一些常用正则表达式
- iPhone开发之.plist文件的创建于使用—— 代码案例 ( 图片浏览器的创建)
- IO流的文件写入与读取
- [MFC]使用强大的第三方串口类 CSerialPort
- 如何清除jsp页面缓存、cookie、session?
- 巧用hidden传递参数
- jquery选择器(原创)<二>
- 如何在 Ubuntu 15.04 系统中安装 Logwatch
- Apache之——命令行启动出现Failed to open the Apache2.2 Service解决方案
- 基于快排 查找数组中出现三次的元素(***)
- response.sendRedirect()与request.getRequestDispatcher().forward()区别
- 软件测试基础_软件缺陷管理学习笔记
- cocos2dx精灵裁剪显示ClippingNode
- Brief introduction to Scala and Breeze for statistical computing
- python一套完整的事务操作
- linux系统常用命令
- html5学习之路_004
- 使用strut2要注意的问题
- 使用了hibernate时候乱码问题