http://m.blog.csdn.net/blog/xiaoaorensheng000/9850339
转载:http://hi.baidu.com/sunguangran/item/6a0949e5a0ff1da8c00d7571
排序算法稳定性讨论文章:http://blog.csdn.net/johnny710vip/article/details/6895654
C++数据结构 排序 二分 插入 冒泡 基数 归并 直选 快排 希尔 堆排序
认真的学习了严蔚敏版的数据结构,感觉应该自己实现一下通用的算法才能有更深入的理解,于是贡献给大家下面这些我自己写的,使用C++模版实现了所有常见的排序算法,所有算法都很短小精悍,gcc编译运行通过(希尔排序除外)。
其中快速排序的代码最短小实用(欢迎各位dx拍砖),last监视哨的思想来自百度百科对qsort的解释----它大大简化了qsort的代码量。后续我将测试所有这些算法性能的情况,并对比C/C++库的标准函数。
(1)2分法查找有序连续内存
template <class C>
int bsearch(C value,iterator begin,iterator end){
iterator mid=& begin[(end-begin)/2];
if(*mid==value)return begin-mid;
else{
if(begin==end)return -1;
if(value<*mid)return bsearch(value,begin,mid);
else return bsearch(value,++mid,end);
}
return -1;
}
int main(void){
int buf2[]={1,3,9,10};
int idx=bsearch<int,int*>(1,buf2,&buf2[3]);
if(idx!=-1)printf("v=%d,pos=%d\n",buf2[idx],idx);
else printf("not found\n");
return 0;
}
(2)插入排序(稳定)----当然,可以用折半插入排序来提高性能
template <class T>
void isort(T begin,size_t length){
size_t l=length*sizeof(*begin);
T s=(T)malloc(l);
s[0]=begin[0];
for(int b=1;b<length;++b){
size_t c=0;
for(;c<b;++c){
if(begin[b]<s[c]){
for(size_t k=b-c;k>0;--k){
s[c+k]=s[c+k-1];
}
break;
}
}
s[c]=begin[b];
}
memcpy(begin,s,l);
delete[] s;
}
main(...)
short buf2[]={11,3,9,10,7,6,15,2};
isort(buf2,8);
for(int i=0;i<sizeof(buf2)/sizeof(short);++i)printf("%d ",buf2[i]);
(3)冒泡排序(稳定)
template <class T>
void bubsort(T s,size_t len){
for(int i=0;i<len-1;++i){//loop count
int op=0;
for(int m=0;m<len-i;++m){
if(s[m]>s[m+1]){
int tmp=s[m];
s[m]=s[m+1];
s[m+1]=tmp;
op=1;
}
}
if(!op)return;
}
}
(4)基数排序:O(nlog(r)m)其中r为所采取的基数,而logr(n)=m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。合理设计r和m的值,可以得到最有解。它利用了每次比较以后得到的历史信息。需要根据需求具体设计,没有通用形式,必须根据具体问题的信息具体设计,例如扑克牌排序等。它的核心思想是利用数据的某方面的特定信息。下面的例子是排序如果各2位正数,使用了10个桶
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iterator>
#include<iostream>
//Radix,Bucket sort
#define DEMICAL 10
int buk[DEMICAL][DEMICAL+1];//bucket
short t[DEMICAL];//top;
int *p;
void getb(size_t b){
printf("\nt[b]=%d,",t[b]);
if(t[b]==0){
printf("buk[%d] is empty",b);
return;
}else{
for(int i=1;i<=t[b];++i){
printf("buk[%d,%d]=%d ",b,i,buk[b][i]);
*p++=buk[b][i];
}
}
}
void getall(){for(int a=0;a<DEMICAL;++a){getb(a);} printf("\n");}
int main(int argc, char *argv[])
{
int pi[]={34,23,53,66,73,81,13,22,5,98,92,2,35,6,78,81,51,20,63,55,31,61,90,27,77};
int l=sizeof(pi)/sizeof(int);
#define PUSH(b,v) buk[b][++t[b]]=v
for(size_t i=0;i<l;++i){//low demical
int hvb=pi[i]%10;
PUSH(hvb,pi[i]);
}
p=pi;
getall();
copy(&pi[0],&pi[l],ostream_iterator<int>(cout," "));
printf("\n");
for(int st=0;st<DEMICAL;++st){t[st]=0;}
for(size_t i=0;i<l;++i){//high demical
int hvb=pi[i]/10;
PUSH(hvb,pi[i]);
}
p=pi;
getall();
copy(&pi[0],&pi[l],ostream_iterator<int>(cout," "));
printf("\n");
return 0;
}
(5)归并排序
template <class T>
void merge(T* begin,T* end,size_t len){
int es=sizeof(*begin);//元素大小
int ss=1;//sub size;//组内元素个数
while(ss<len){
int gs=ss<<1;
int group=len/gs+len%gs;//分组个数
if(gs>group)group=1;
printf("gsize=%d,group=%d,ss=%d===========\n",gs,group,ss);
for(int i=0;i<group;++i){
T* left=&begin[i*gs];
T* mid =&begin[i*gs+gs];
if(i==group-1)mid=end;//always process end element
mergesort<T*>(left,mid,end);//由于两部分已经有序,因此可以使用mergeList方法来实现合并
}
ss<<=1;
}
}
归并的递归实现
void merge(T* begin,T*end){
int* mid=(int*)( ( (int)begin+(int)end )/2 );
if(begin!=mid)merge(begin,mid);
if(mid!=end) merge(++mid,end);
mergesort<T*>(begin,mid,end);//实现方法同上
}
(6)直接选择排序(不稳定)
/*用法
int buf[]={7,3,5,2,4,9,3,12,1,6};
csort(buf,&buf[10]);
*/
template <class T>
void csort(T* begin,T* end){
for(T* b=begin;b!=end;++b){
T* n=b;
++n;
bool op=false;
while(n!=end){
T v=*b;
if(*n<v){
*n^=*b;
*b^=*n;
*n^=*b;
op=true;
}
++n;
}
if(op==false)return;
}
}
(7)快速排序(不稳定)----如果您的实现比我的更简短,欢迎对比:)
/*用法
int buf[]={17,3,15,2,4,9,3,12,1,6};
qsort(&buf[0],&buf[10]);
copy(&buf[0],&buf[10],ostream_iterator<int>(cout," "));
*/
#define swap(x,y) (x)^=(y);(y)^=(x);(x)^=(y)
template <class T>
void qsort(T begin,T end){
T left=begin;
if(++left>=end)return;//只有一个元素了
size_t m= ( (size_t)end-(size_t)begin )/(2*sizeof(T));//STL里面这个中间位置是怎么计算的? int*并没有distace和advance这样对应的迭代方法... ...
T mid=&begin[m];
swap(*begin,*mid);
T last=left;
for(;left!=end;++left){
if(*begin>*left){//找到了更小的数
if(left!=last){
swap(*left,*last);
}
++last;
}
}
qsort(begin,last);
qsort(last,end);
}
(8)希尔排序(不稳定)
可以理解为直接插入排序的变体。这里只给出伪代码:
首先实现一个直接插入排序
void isort(*begin,size_t offset,size_t number);
这里offset是插入排序的间隔,number是插入排序的元素个数
void shellsort(T begin,T end,size_t s){
for(int g=sqr(s);g>1;g=sqr(g)){//分组
size_t gs=s/g;//gs 是 group size
for(int n=0;n<gs;++n){//每次分组以后,处理某个组里面全部的元素
isort(begin+n*g, g, g);
}//每个组的所有元素
if(gs*g<s)isort(begin+gs*g,g,s-gs*g);//末尾剩余的元素
}//若干个组
}
(9)最后隆重推出百万级俱乐部成员: 堆排序。程序模板在gcc3.4.2下验证通过
#include<cstdio>
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<iterator>
using namespace std;
#define swap(x,y) (x)^=(y);(y)^=(x);(x)^=(y)
template <class T>
void hadjust(T heap,size_t len){
size_t sub=len/2;//不大于n/2的整数
while(sub){
size_t left =sub<<1;
size_t right=left+1;
int csub;//需要交换的子节点
if(right>len)csub=left;
else csub=heap[left-1]>heap[right-1]?left:right;
if(heap[sub-1]>=heap[csub-1]){
--sub;
continue;
}
swap(heap[sub-1],heap[csub-1]);
--sub;
}
}
template <class T>
void hsort(T heap,size_t s){
while(s>1){
hadjust<T>(heap,s);
swap(heap[0],heap[s-1]);
--s;
}
}
int main(void){
int buf[]={17,3,15,2,4,9,3,12,1,6,8,12};
hsort(buf,12);
copy(&buf[0],&buf[12],ostream_iterator<int>(cout," "));
system("PAUSE");
return 0;
}
#include "iostream.h"
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
/*******************************************************************************
冒泡排序
*******************************************************************************/
long Bubblesort(long R[], long n)
{
int flag=1;
//当flag为0,则停止排序
long BC=0;
for(long i=1;i<n;i++)
{
//i表示趟数,最多n-1趟
flag=0;
//开始时元素未交换
for(long j=n-1;j>=i;j--)
{
if(R[j]<R[j-1])
//发生逆序
{
long t=R[j];
R[j]=R[j-1];
R[j-1]=t;flag=1; //交换,并标记发生了交换
}
BC++;
}
}
return BC;
}
/*******************************************************************************
选择排序
*******************************************************************************/
long selectsort(long R[], long n)
{
long i,j,m;long t,SC=0;
for(i=0;i<n-1;i++)
{
m=i;
for(j=i+1;j<n;j++)
{
SC++;
if(R[j]<R[m]) m=j;
if(m!=i)
{
t=R[i];
R[i]=R[m];
R[m]=t;
}
}
}
return SC;
}
/*******************************************************************************
直接插入排序
*******************************************************************************/
long insertsort(long R[], long n)
{
long IC=0;
for(long i=1;i<n;i++)
//i表示插入次数,共进行n-1次插入
{
long temp=R[i];
//把待排序元素赋给temp
long j=i-1;
while((j>=0)&&(temp<R[j]))
{
R[j+1]=R[j];j--;
//顺序比较和移动
IC++;
}
IC++;
R[j+1]=temp;
}
return IC;
}
/*******************************************************************************
希尔排序
*******************************************************************************/
long ShellSort(long R[], int n)
{
int temp,SC=0;
for(int i = n / 2; i > 0; i /= 2)
//将所有记录分成增量为t的子序列
{
for(int j = 0; j < i; j ++)
//对每个子序列进行插入排序
for(int k = j + i; k < n; k += i)
//依次将记录插入有序子序列中
for(int p = j; p < k; p += i)
//循环查找要插入的位置
if (R[k] < R[p]) {
temp = R[k];
for(int q = k; q > p; q -= i){
//插入位置以后的记录依次后移
R[q] = R[q - i];
SC++;
}
R[p] = temp;
//插入记录
break;
}
}
return SC;
}
/*******************************************************************************
快速排序
*******************************************************************************/
long quicksort(long R[], long left, long right)
{
static long QC=0;
long i=left,j=right;
long temp=R[i];
while(i<j)
{
while((R[j]>temp)&&(j>i))
{
QC++;
j=j-1;
}
if(j>i)
{
R[i]=R[j];
i=i+1;
QC++;
}
while((R[i]<=temp)&&(j>i))
{
QC++;
i=i+1;
}
if(i<j)
{
R[j]=R[i];
j=j-1;
QC++;
}
}
//二次划分得到基准值的正确位置
R[i]=temp;
if(left<i-1)
quicksort(R,left,i-1);
//递归调用左子区间
if(i+1<right)
quicksort(R,i+1,right);
//递归调用右子区间
return QC;
}
/*******************************************************************************
堆排序
*******************************************************************************/
static long HC=0;
void Heap(long R[], int n)
//重新构造小顶堆
{
int temp;
for(int i = 0; i * 2 < n; i ++)
{
if (R[i] >= R[2 * i] && R[2 * i]) {
temp = R[i];
R[i] = R[2 * i];
R[2 * i] = temp;
HC++;
}
if (R[i] >= R[2 * i + 1] && R[2 * i + 1]) {
temp = R[i];
R[i] = R[2 * i + 1];
R[2 * i + 1] = temp;
HC++;
}
}
}
long HeapSort(long R[], int n)
//取出堆顶
{
for(int i = n - 1; i >= 0; i --)
{
Heap(R, i);
R[0] = R[i];
}
return HC;
}
/*******************************************************************************
归并排序
*******************************************************************************/
static long MC=0;
void Merge(long c[], long d[], int l, int m, int r)
{//合并c[1:m]和c[m+1:r]到d[1:r]
int i = l, j = m + 1, k = l;
while ((i <= m) && (j <= r)) {
if (c[i] <= c[j])
d[k ++] = c[i ++];
else
d[k ++] = c[j ++];
MC++;
}
if (i > m)
for(int q = j; q <= r; q ++)
d[k ++] = c[q];
else
for(int q = i; q <= m; q ++)
d[k ++] = c [q];
}
void Copy(long a[], long b[], int left, int right)
{
for(int i = left; i <= right; i ++)
a[i] = b[i];
}
long MergeSort(long a[], int left, int right)
{//递归将数组分成子数组
long* b = new long [right + 1];
if (left < right) {
int i = (left + right) / 2;
MergeSort(a, left, i);
MergeSort(a, i + 1, right);
Merge(a, b, left, i, right);
Copy(a, b, left, right);
}
return MC;
}
/*******************************************************************************
基数排序
*******************************************************************************/
class node
//结点类
{
friend class list;
public:
int value;
node* next;
node(){value = 0; next = NULL;}
protected:
private:
};
class list
//链表类
{
public:
void Insert(list& L, int value);
node* head;
list(){head = NULL;}
protected:
private:
};
void list::Insert(list &L, int value)
//插入结点
{
node* N = new node;
N->value = value;
if (!L.head) {
L.head = N;
}
else {
node* p = L.head;
while (p->next) {
p = p->next;
}
p->next = N;
}
}
long RadixSort(long R[], int n)
{
list a[10];
int i,RC=0;;
for(int t = 1; t < 1000; t *= 10)
{
for(i = 0; i < 10; i ++)
{
int j = R[i] / t % 10;
a[j].Insert(a[j], R[i]);
}
int n = 0;
for(i = 0; i < 10; i ++)
{
node* p = a[i].head;
while (p) {
R[n] = p->value;
p = p->next;
n ++;
}
a[i].head = NULL;
}
}
return RC;
}
/*******************************************************************************
操作选择函数
*******************************************************************************/
void operate(long a[], long n)
{
long * R = new long [n];
time_t start, end;
double dif;
long degree;
char ch;
cout << "请选择排序算法:\t";
cin >> ch;
switch(ch){
case '1':
{
for(int i = 0; i < n; i ++)
{
R[i] = a[i];
}
time(&start);
degree = Bubblesort(R, n);
time(&end);
dif = difftime(end, start);
cout << "冒泡排序所用时间:\t" << dif << '\n';
cout << "冒泡排序交换次数:\t" << degree << '\n';
cout << '\n';
operate(a, n);
break;
}
case '2':
{
for(int i = 0; i < n; i ++)
{
R[i] = a[i];
}
time(&start);
degree = selectsort(R, n);
time(&end);
dif = difftime(end, start);
cout << "选择排序所用时间:\t" << dif << '\n';
cout << "选择排序交换次数:\t" << degree << '\n';
cout << '\n';
operate(a, n);
break;
}
case '3':
{
for(int i = 0; i < n; i ++)
{
R[i] = a[i];
}
time(&start);
degree = insertsort(R, n);
time(&end);
dif = difftime(end, start);
cout << "直接插入排序所用时间: " << dif << '\n';
cout << "直接插入排序交换次数: " << degree << '\n';
cout << '\n';
operate(a, n);
break;
}
case '4':
{
for(int i = 0; i < n; i ++)
{
R[i] = a[i];
}
time(&start);
degree = ShellSort(R, n);
time(&end);
dif = difftime(end, start);
cout << "希尔插入排序所用时间: " << dif << '\n';
cout << "希尔插入排序交换次数: " << degree << '\n';
cout << '\n';
operate(a, n);
break;
}
case '5':
{
for(int i = 0; i < n; i ++)
{
R[i] = a[i];
}
time(&start);
degree = quicksort(R, 0, n - 1);
time(&end);
dif = difftime(end, start);
cout << "快速排序所用时间:\t" << dif << '\n';
cout << "快速排序交换次数:\t" << degree << '\n';
cout << '\n';
operate(a, n);
break;
}
case '6':
{
for(int i = 0; i < n; i ++)
{
R[i] = a[i];
}
time(&start);
degree = HeapSort(R, n);
time(&end);
dif = difftime(end, start);
cout << "堆排序所用时间:\t" << dif << '\n';
cout << "堆排序交换次数:\t" << degree << '\n';
cout << '\n';
operate(a, n);
break;
}
case '7':
{
for(int i = 0; i < n; i ++)
{
R[i] = a[i];
}
time(&start);
degree = MergeSort(R, 0, n);
time(&end);
dif = difftime(end, start);
cout << "归并排序所用时间:\t" << dif << '\n';
cout << "归并排序比较次数:\t" << degree << '\n';
cout << '\n';
operate(a, n);
break;
}
case '8':
{
for(int i = 0; i < n; i ++)
{
R[i] = a[i];
}
time(&start);
degree = RadixSort(R, n);
time(&end);
dif = difftime(end, start);
cout << "基数排序所用时间:\t" << dif << '\n';
cout << "基数排序交换次数:\t" << degree << '\n';
cout << '\n';
operate(a, n);
break;
}
case '9':
break;
default:
{
cout << "输入错误,请选择正确的操作!" << '\n';
break;
}
}
}
/*******************************************************************************
主函数
*******************************************************************************/
void main()
{
cout<<"\n** 排序算法比较 **"<<endl;
cout<<"===================================================="<<endl;
cout<<"** 1 --- 冒泡排序 **"<<endl;
cout<<"** 2 --- 选择排序 **"<<endl;
cout<<"** 3 --- 直接插入排序 **"<<endl;
cout<<"** 4 --- 希尔排序 **"<<endl;
cout<<"** 5 --- 快速排序 **"<<endl;
cout<<"** 6 --- 堆排序 **"<<endl;
cout<<"** 7 --- 归并排序 **"<<endl;
cout<<"** 8 --- 基数排序 **"<<endl;
cout<<"** 9 --- 退出程序 **"<<endl;
cout<<"===================================================="<<endl;
cout << "\n请输入要产生的随机数的个数:";
long n;
cin >> n;
cout << endl;
long *a = new long [n];
srand((unsigned long)time(NULL));
for (long i = 0; i < n; i ++)
{
a[i] = rand() % n;
}
operate(a, n);
}