排序算法——希尔 冒泡 快速 插入 归并 基数







http://m.blog.csdn.net/blog/xiaoaorensheng000/9850339

转载:http://hi.baidu.com/sunguangran/item/6a0949e5a0ff1da8c00d7571




排序算法稳定性讨论文章:http://blog.csdn.net/johnny710vip/article/details/6895654
快速排序、希尔排序堆排序、直接选择排序不是稳定的排序算法
基数排序冒泡排序直接插入排序、折半插入排序归并排序是稳定的排序算法
   
   

排序算法稳定性

概念
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。

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);
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值