C++数据结构 排序 二分 插入 冒泡 基数 归并 直选 快排 希尔 堆排序
2011-06-28 00:27
591 查看
原文地址:http://hi.baidu.com/sunguangran/blog/item/f972073465c0b347241f1425.html
认真的学习了严蔚敏版的数据结构,感觉应该自己实现一下通用的算法才能有更深入的理解,于是贡献给大家下面这些我自己写的,使用C++模版实现了所有常见的排序算法,所有算法都很短小精悍,gcc编译运行通过(希尔排序除外)。
其中快速排序的代码最短小实用(欢迎各位dx拍砖),last监视哨的思想来自百度百科对qsort的解释----它大大简化了qsort的代码量。后续我将测试所有这些算法性能的情况,并对比C/C++库的标准函数。
(1)2分法查找有序连续内存
(2)插入排序(稳定)----当然,可以用折半插入排序来提高性能
(3)冒泡排序(稳定)
(4)基数排序:O(nlog(r)m)其中r为所采取的基数,而logr(n)=m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。合理设计r和m的值,可以得到最有解。它利用了每次比较以后得到的历史信息。需要根据需求具体设计,没有通用形式,必须根据具体问题的信息具体设计,例如扑克牌排序等。它的核心思想是利用数据的某方面的特定信息。下面的例子是排序如果各2位正数,使用了10个桶
(5)归并排序
(6)直接选择排序(不稳定)
(7)快速排序(不稳定)----如果您的实现比我的更简短,欢迎对比:)
(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下验证通过
认真的学习了严蔚敏版的数据结构,感觉应该自己实现一下通用的算法才能有更深入的理解,于是贡献给大家下面这些我自己写的,使用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; }
// HeapSortTest.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #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 _tmain(int argc, _TCHAR* argv[]) { // int buf[]={17,3,15,2,4,9,3,12,1,6,8,12}; int buf[]={40,55,49,73,12,27,98,81,64,36}; hsort(buf,10); copy(&buf[0],&buf[10],ostream_iterator<int>(cout," ")); cout<<endl; return 0; }
相关文章推荐
- c++实现数据结构中的各种排序方法:直接插入、选择,归并、冒泡、快速、堆排序、shell排序
- c# 自定义排序类(冒泡、选择、插入、希尔、快速、归并、堆排序等)
- 九大排序算法及其实现- 插入.冒泡.选择.归并.快速.堆排序.计数.基数.桶排序.堆排序
- java---插入排序,冒泡,归并,快速,希尔,堆排序
- 链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)
- 数据结构 27 排序 排序-选择 插入 冒泡 希尔 快速归并 6种排序
- 数据结构学习笔记排序 (冒泡、插入、希尔、堆排序、归并排序)
- 数据结构各种排序法及核心思想(冒泡、鸡尾酒、选择、插入、二分法、希尔、堆、归并、快速)
- 插入 希尔 排序 堆排序 冒泡 快速 归并
- 链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)
- 数据结构(C#)--冒泡、插入、快速、堆、归并、希尔、选择各种排序排序过程比较以及各种排序的所用时间的对比
- 链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)
- 排序 简单排序(冒泡,插入)先进排序(快排,归并)堆排序,基数排序
- 链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)
- 数据结构 学习笔记(十):排序(上):简单排序(冒泡,插入),希尔 / 选择 / 堆 / 归并 排序
- 链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)【转载】
- C++实现各种基础排序(冒泡、选择、快排、插入、堆排、希尔、归并)
- 十种排序算法总结(冒泡、插入、选择、希尔、归并、堆、快速,计数,桶,基数)
- 【算法与数据结构】冒泡、插入、归并、堆排序、快速排序的Java实现代码
- 常见排序算法总结与实现(冒泡、插入、选择、希尔、堆排序、归并、快排)