各种内排序算法的C++实现(转)

 和很多计算机系的同学们一样,我在大学二年级时也学了《数据结构》这门课。当时我的老师是一个中科大的博士,现在已经是教授了。他在课上曾经这样评价这门课:《数据结构》几乎是所有计算机课程的基础课,如果把这门课学好了,其他的专业课就不成问题了。还有,IT公司的面试经常涉及到数据结构的相关知识,该课程的重要性由此可见。但是当时年少无知根本没好好学习,等到笔试,面试时才幡然悔悟。下面的内排序算法可算是数据结构中的重要内容,程序代码全部用C++实现,已在visual C++6.0上运行过了。

一.插入排序(insert sorting)

最差情况下,直接插入排序的最大时间代价为θ(n²),最小时间代价为θ(n),平均时间代价为θ(n²)。

#include <iostream>  
using namespace std;  

/*交换函数,作用是交换数组中的两个元素的位置*/  
void swap(int array[],int i,int j)  
{  
    int tmp=array[i];  
    array[i]=array[j];  
    array[j]=tmp;  
}  

/*插入排序*/  
void InsertSort(int array[],int n)  
{  
    for(int i=1;i<n;i++)  
    {  
        for(int j=i;j>0;j--)  
        {  
            if(array[j]>array[j-1])  
                swap(array,j,j-1);  
            else  
                break;  
        }  
    }  
}  

int main()  
{  
    int array[5]={3,1,2,5,4};  
    InsertSort(array,5);  
    for(int i=0;i<5;i++)  
        cout<<array[i]<<"  ";  
    cout<<endl;  
    return 0;  
}  

二.冒泡排序(bubble sorting)

冒泡排序的最大时间代价,最小时间代价和平均时间代价均为θ(n²)。

#include <iostream>  
using namespace std;  

/*交换函数,作用是交换数组中的两个元素的位置*/  
void swap(int array[],int i,int j)  
{  
    int tmp=array[i];  
    array[i]=array[j];  
    array[j]=tmp;  
}  

/*冒泡排序*/  
void BubbleSort(int array[],int n)  
{  
    for(int i=0;i<n-1;i++)  
    {  
        for(int j=n-1;j>i;j--)  
        {  
            if(array[j]<array[j-1])  
                swap(array,j,j-1);  
        }  
    }  
}  

int main()  
{  
    int array[5]={3,1,2,5,4};  
    BubbleSort(array,5);  
    for(int i=0;i<5;i++)  
        cout<<array[i]<<"  ";  
    cout<<endl;  
    return 0;  
}  

三.选择排序(selection sorting)

选择排序的最大时间代价,最小时间代价和平均时间代价均为θ(n²)。选择排序不依赖于原始数组的输入顺序。

#include <iostream>  
using namespace std;  

/*交换函数,作用是交换数组中的两个元素的位置*/  
void swap(int array[],int i,int j)  
{  
    int tmp=array[i];  
    array[i]=array[j];  
    array[j]=tmp;  
}  

/*选择排序*/  
void SelectionSort(int array[],int n)  
{  
    for(int i=0;i<n-1;i++)  
    {  
        int smallest=i;  
        for(int j=i+1;j<n;j++)  
        {  
            if(array[smallest]>array[j])  
                smallest=j;  
        }  
        swap(array,i,smallest);  
    }  
}  

int main()  
{  
    int array[5]={3,1,2,5,4};  
    SelectionSort(array,5);  
    for(int i=0;i<5;i++)  
        cout<<array[i]<<"  ";  
    cout<<endl;  
    return 0;  
}  

四.shell sorting

增量为2的shell排序的时间代价可以达到θ(n的3/2次方),有的增量可以达到θ(n的7/6次方),很接近θ(n)。

#include <iostream>  
using namespace std;  

/*交换函数,作用是交换数组中的两个元素的位置*/  
void swap(int array[],int i,int j)  
{  
    int tmp=array[i];  
    array[i]=array[j];  
    array[j]=tmp;  
}  

/*希尔排序*/  
void ShellSort(int array[],int n)  
{  
    for(int delta=n/2;delta>0;delta/=2)  
    {  
        for(int i=0;i<delta;i++)  
        {  
            for(int j=i+delta;j<n;j+=delta)  
            {  
                for(int k=j;k>0;k-=delta)  
                {  
                    if(array[k]<array[k-1])  
                        swap(array,k,k-1);  
                }  
            }  
        }  
    }  
}  

int main()  
{  
    int array[8]={6,8,7,3,1,2,5,4};  
    ShellSort(array,8);  
    for(int i=0;i<8;i++)  
        cout<<array[i]<<"  ";  
    cout<<endl;  
    return 0;  
}  

五.快速排序(quick sorting)

快速排序的最大时间代价为θ(n²),最小时间代价为θ(n*logn),平均时间代价为θ(n*logn)。注意:快速排序是一种不稳定的排序方式,其性能依赖于原始数组的有序程度,更进一步分析,就是依赖与轴值元素的选择。快排的比较次数远多于移动次数,所以主要考虑比较次数。
快排中,每一次比较可以确定一个轴值元素的位置。若p[m,q,n](q为轴值元素)。当然确定第一个轴值元素也是要比较(n-m-1)次。但第二个轴值元素,第三个轴值元素就要进行(q-m-1)和(n-q-1)次比较。如果q的值若为m或n,快速排序就退化成冒泡排序了,快排就没有什么优势了。

#include <iostream>  
using namespace std;  

/*交换函数,作用是交换数组中的两个元素的位置*/  
void swap(int array[],int i,int j)  
{  
    int tmp=array[i];  
    array[i]=array[j];  
    array[j]=tmp;  
}  

/*将轴值放到数组的适当的位置*/  
int partition(int array[],int left,int right)  
{  
    int mid=(left+right)/2;  
    int tmp=array[mid];  
    swap(array,mid,right);  
    int i=left;  
    int j=right;  
    while(1)  
    {  
        /*i指针向右移动,直到找到一个大于轴值的值*/  
        while(1)  
        {  
            /*如果i与j相遇则确定轴值位置,将其返回*/  
            if(i==j)  
            {  
                array[i]=tmp;  
                return i;  
            }  
            if(array[i]>tmp)  
            {  
                array[j]=array[i];  
                j--;  
                break;  
            }  
            i++;  
        }  
        /*j指针向左移动,直到找到一个小于轴值的值*/  
        while(1)  
        {  
            /*如果i与j相遇则确定轴值位置,将其返回*/  
            if(i==j)  
            {  
                array[j]=tmp;  
                return j;  
            }  
            if(array[j]<tmp)  
            {  
                array[i]=array[j];  
                i++;  
                break;  
            }  
            j--;  
        }  
    }  
}  

/*快速排序*/  
void quickSort(int array[],int left,int right)  
{  
    if(right<=left)  
        return;  
    int pivot=partition(array,left,right);  
    quickSort(array,left,pivot-1);  
    quickSort(array,pivot+1,right);  
}  

int main()  
{  
    int array[8]={6,8,7,3,1,2,5,4};  
    quickSort(array,0,7);  
    for(int i=0;i<8;i++)  
        cout<<array[i]<<"  ";  
    cout<<endl;  
    return 0;  
}  

六.归并排序(merge sorting)

归并排序的最大时间代价,最小时间代价和平均时间代价均为θ(n*logn)。归并排序不依赖于原始数组的有序程度。

#include <iostream>  
using namespace std;  

/*归并过程--将两个有序数组合并成一个有序数组*/  
void merge(int array[],int tempArray[],int left,int right,int middle)  
{  
    int index1=left;  
    int index2=middle+1;  
    for(int i=left;(index1<=middle)&&(index2<=right);i++)  
    {  
        if(array[index1]<array[index2])  
            tempArray[i]=array[index1++];  
        else  
            tempArray[i]=array[index2++];  
    }  
    while(index1<=middle)  
        tempArray[i++]=array[index1++];  
    while(index2<=right)  
        tempArray[i++]=array[index2++];  
    for(i=left;i<=right;i++)  
        array[i]=tempArray[i];    
}  

/*两路归并排序--array[]为待排数组,tempArray[]为临时数组,leftright分别是数组两端*/  
void mergeSort(int array[],int tempArray[],int left,int right)  
{  
    if(left<right)  
    {  
        int middle=(left+right)/2;  
        mergeSort(array,tempArray,left,middle);  
        mergeSort(array,tempArray,middle+1,right);  
        merge(array,tempArray,left,right,middle);  
    }  
}  

int main()  
{  
    int array[8]={6,8,7,3,1,2,5,4};  
    int tempArray[8];  
    mergeSort(array,tempArray,0,7);  
    for(int i=0;i<8;i++)  
        cout<<array[i]<<"  ";  
    cout<<endl;  
    return 0;  
}  

七.堆排序(heap sorting)

堆排序的最大时间代价,最小时间代价和平均时间代价均为θ(n*logn)。堆排序和归并排序一样,不依赖于原始数组的有序程度。

#include <iostream>  
#include "MaxHeap.h"  
using namespace std;  

/*最大堆排序函数*/  
void heapSort(int array[],int n)  
{  
    MaxHeap max_heap=MaxHeap(array,n);  

    /*删除堆的最大值(堆顶),即每次将最大值与数组的最后一个元素交换位置*/  
    for(int i=0;i<7;i++)  
        max_heap.removeMax();  
}  

int main()  
{  
    int array[8]={4,3,7,1,2,8,5,6};  
    heapSort(array,8);  
    for(int i=0;i<8;i++)  
        cout<<array[i]<<"  ";  
    cout<<endl;  
    return 0;  
}  




MaxHeap.h
#include <iostream>  
using namespace std;  

/*最大堆定义*/  
class MaxHeap  
{  
private:  
    int size; //最大堆的元素数目  
int * array;  //最大堆数组的首地址指针  
public:  
    MaxHeap(int array[],int n); //用已有数组初始化一个最大堆   
         void buildHeap();   //构建最大堆  
    void siftDown(int index);  //向下筛选法  
    void swap(int index1,int index2);  //交换位置为index1与index2的元素  
    void removeMax();  //删除堆顶的最大值--与数组最后一个元素交换位置并重新构建最大堆  
    int leftChild(int index);  //返回左孩子的位置  
    int rightChild(int index);  //返回右孩子的位置  
};  




MaxHeap.cpp


#include <iostream>  
#include "MaxHeap.h"  
using namespace std;  

/*最大堆成员函数实现*/  
MaxHeap::MaxHeap(int array[],int n)  
{  
    this->array=array;  
    size=n;  
    buildHeap();  
}  

void MaxHeap::buildHeap()  
{  
    for(int i=size/2-1;i>=0;i--)  
        siftDown(i);  
}  

void MaxHeap::siftDown(int index)  
{  
    int max_index=leftChild(index);  
    while(max_index<size)  
    {  
        if(max_index<size-1&&array[rightChild(index)]>array[max_index])  
            max_index++;  
        if(array[index]>array[max_index])  
            break;  
        swap(index,max_index);  
        index=max_index;  
        max_index=leftChild(index);  
    }  
}  

void MaxHeap::swap(int index1,int index2)  
{  
    int temp=array[index1];  
    array[index1]=array[index2];  
    array[index2]=temp;  
}  

void MaxHeap::removeMax()  
{  
    swap(0,size-1);  
    size--;  
    siftDown(0);  
}  

int MaxHeap::leftChild(int index)  
{  
    return index*2+1;  
}  

int MaxHeap::rightChild(int index)  
{  
    return index*2+2;  
}  

八.基数排序(radix sorting)

基数排序的时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。基数排序法是属于稳定性的排序。

#include <iostream>  
using namespace std;  

/*计算关键字位数的最大值*/  
int KeySize(int array[],int size)  
{  
    int key_size=1;  

    for(int i=0;i<size;i++)  
    {  
        int temp=1;  
        int n=10;  
        while(array[i]/n>0)  
        {  
            temp++;  
            n*=10;  
        }  
        key_size=(temp>key_size)?temp:key_size;  
    }  
    return key_size;  
}  

/*基数排序*/  
void RadixSort(int array[],int size)  
{  
    int bucket[10][10]={0};//定义基数桶  
    int order[10]={0};//保存每个基数桶之中的元素个数  
    int key_size=KeySize(array,size);//计算关键字位数的最大值  

    for(int n=1;key_size>0;n*=10,key_size--)  
    {  
        /*将待排序的元素按照关键值的大小依次放入基数桶之中*/  
        for(int i=0;i<size;i++)  
        {  
            int lsd=(array[i]/n)%10;  
            bucket[lsd][order[lsd]]=array[i];  
            order[lsd]++;  
        }  

        /*将基数桶中的元素重新串接起来*/  
        int k=0;  
        for(i=0;i<10;i++)  
        {  
            if(order[i]!=0)  
            {  
                for(int j=0;j<order[i];j++)  
                {  
                    array[k]=bucket[i][j];  
                    k++;  
                }  
                order[i]=0;  
            }  
        }  
    }  
}  

int main()  
{  
    int array[10]={73,22,93,43,55,14,28,65,39,81};  
    int size=sizeof(array)/sizeof(int);  
    RadixSort(array,size);  
    for(int i=0;i<size;i++)  
        cout<<array[i]<<"  ";  
    cout<<endl;  
    return 0;  
}  
 下面我们来讨论一下各种排序算法的稳定度,稳定排序算法会依照相等的关键(换言之就是值)维持纪录的相对次序。也就是一个排序算法是稳定的,就是当有两个有相等关键的纪录R和S,且在原本的串列中R出现在S之前,在排序过的串列中R也将会是在S之前。

  一般的方法:插入、交换、选择、合并等等。交换排序包含冒泡排序(bubble sort)和快速排序(quicksort)。选择排序包含shaker排序和堆排序(heapsort)。

  当相等的元素是无法分辨的,比如像是整数,稳定度并不是一个问题。然而,假设以下的数对将要以他们的第一个数字来排序。

  (4, 1) (3, 1) (3, 7) (5, 6)

  在这个状况下,有可能产生两种不同的结果,一个是依照相等的键值维持相对的次序,而另外一个则没有:

  (3, 1) (3, 7) (4, 1) (5, 6) (维持次序)

  (3, 7) (3, 1) (4, 1) (5, 6) (次序被改变)

  不稳定排序算法可能会在相等的键值中改变纪录的相对次序,但是稳定排序算法从来不会如此。不稳定排序算法可以被特别地时作为稳定。作这件事情的一个方式是人工扩充键值的比较,如此在其他方面相同键值的两个物件间之比较,就会被决定使用在原先资料次序中的条目,当作一个同分决赛。然而,要记住这种次序通常牵涉到额外的空间负担。

稳定的排序算法:

  冒泡排序(bubble sort) — O(n2)

  鸡尾酒排序 (Cocktail sort, 双向的冒泡排序) — O(n2)

  插入排序 (insertion sort)— O(n2)

  桶排序 (bucket sort)— O(n); 需要 O(k) 额外 记忆体

  归并排序 (merge sort)— O(n log n); 需要 O(n) 额外记忆体

  原地归并排序 — O(n2)

  二叉树排序 (Binary tree sort) — O(n log n); 需要 O(n) 额外记忆体

  基数排序 (radix sort)— O(n·k); 需要 O(n) 额外记忆体

不稳定的排序算法:

  选择排序 (selection sort)— O(n2)

  希尔排序 (shell sort)— O(n log n) 如果使用最佳的现在版本

  Comb sort — O(n log n)

  堆排序 (heapsort)— O(n log n)

  Smoothsort — O(n log n)

  快速排序 (quicksort)— O(n log n) 期望时间, O(n2) 最坏情况; 对於大的、乱数串列一般相信是最快的已知排序

  一般来说:存在不相邻交换的排序算法是不稳定的,相邻交换的排序算法是稳定的;对于相邻交换的稳定排序算法,通过控制交换条件可以转换成不稳定排序算法;冒泡、插入、归并和基数排序是稳定的;选择、快速、希尔和堆排序是不稳定的。

转载自:http://blog.csdn.net/piaojun_pj/article/details/5911914

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值