南京邮电大学算法与设计实验一:分治策略(最全最新,与题目要求一致)

实验原理:

1、用分治法实现一组无序序列的两路合并排序和快速排序。要求清楚合并排序及快速排序的基本原理,编程实现分别用这两种方法将输入的一组无序序列排序为有序序列后输出。

2、采用基于“五元中值组取中值分割法”(median-of-median-of-five partitioning)的线性时间选择算法,找出N个元素集合S中的第k个最小的元素,使其在线性时间内解决。(参考教材5.5.3节)

实验内容:

1、两路合并排序和快速排序

(1)排序是数据处理中常用的重要手段,是指将一个元素序列调整为按指定关键字值的递增(或递减)次序排列的有序序列。用分治法求解排序问题的思路是,按某种方式将序列分成两个或多个子序列,分别进行排序,再将已排序的子序列合并成一个有序序列。合并排序和快速排序是两种典型的符合分治策略的排序算法。

(2)如果采用顺序存储的可排序表作为算法实现的数据结构,则需要定义一个可排序表类SortableList,两路合并算法和快速排序算法均由定义在该类上的函数实现。

//可排序表类的定义
class SortableList
{
    public:
        SortableList(int mSize)
        {
        maxSize=mSize;
        l=new int[maxSize];
        n=0; //数组中已有元素个数
        }
        ~SortableList()
        {
            delete []l;
        }
        void Input()
        {
                int i;
                for(i=0;i<maxSize;i++)
                    cin>>l[i];
        }
        void Output()
        {
                int i;
                for(i=0;i<maxSize;i++)
                    cout<<l[i]<<", ";
                    cout<<endl;
        }
    private:
        int *l;
        int maxSize;
        int n;
};

(3)结合书上已有的程序代码,使用分治法的两路合并排序算法,实现对初始序列的排序

class SortableList
{
    public:
        SortableList(int mSize,int num)
        {
        maxSize=mSize;
        l=new int[maxSize];
        n=num; //数组中已有元素个数
        }
    
        ~SortableList()
        {
            delete []l;
        }
        void Input()
        {
            int i;
            cout << "请输入待排序的数组:";
            for(i=0;i<n;i++)
                cin>>l[i];
        }
        void Output()
        {
            int i;
            for(i=0;i<n;i++)
                cout<<l[i]<<", ";
            cout<<endl;
        }
    //两路合并算法
        void MergeSort()
        {
            MergeSort(0, n-1);
        }
    
    private:
        int *l;
        int maxSize;
        int n;
    //两路合并排序算法
    void MergeSort(int left,int right)
    {
        if(left<right){                 //若序列长度超过1则划分成2个子序列
            int mid = (left+right)/2;   //将待排序序列一分为二
            MergeSort(left,mid);        //对左子序列排序
            MergeSort(mid+1, right);    //对右子序列排序
            Merge(left, mid, right);    //将2个序列合并
        }
    }
    //将2个有序序列合成一个有序序列的Merge函数
    void Merge(int left,int mid,int right)
    {
        int *temp = new int [right-left+1];
        int i=left,j=mid+1,k=0;
            while(i<=mid && j<=right){
                if(l[i]<l[j])
                    temp[k++]=l[i++];
                else
                    temp[k++]=l[j++];
            }
            while(i<=mid)
                temp[k++]=l[i++];
            while(j<=right)
                temp[k++]=l[j++];
            for(i=0;i<k;i++){
                l[left++]=temp[i];
            }
    }
};

int main()
{
    int num;
    cout << "请输入待排序的数组个数:";
    cin >> num;
    SortableList List(20,num);
    List.Input();
    cout << "合并排序前的结果为:";
    List.Output();
    List.MergeSort();
    cout << "合并排序后的结果为:";
    List.Output();
    return 0;
}

实验结果:

由实验结果可得知两路合并排序算法成功

(4)结合书上已有的程序代码,使用分治法的快速排序算法,实现对初始序列的排序。

//快速排序算法
class SortableList
{
    public:
        SortableList(int mSize,int num)
        {
            maxSize=mSize;
            l=new int[maxSize];
            n=num; //数组中已有元素个数
        }
        ~SortableList()
        {
            delete []l;
        }
        void Input()
        {
            int i;
            cout << "请输入待排序的数组:";
            for(i=0;i<n;i++)
                cin>>l[i];
        }
        void Output()
        {
            int i;
            for(i=0;i<n;i++)
                cout<<l[i]<<", ";
            cout<<endl;
        }
    //快速排序算法
    void QuickSort()
    {
        QuickSort(0, n-1);
    }
    
    private:
        int *l;
        int maxSize;
        int n;
    void Swap(int i,int j)//交换下标i、j的数组
    {
    int c=l[i];
    l[i]=l[j];
    l[j]=c;
    }
    //快速排序算法的实现
    void QuickSort(int left,int right)
    {
        if (left<right)
        {
        int j=Partition(left,right);
        QuickSort(left,j-1);
        QuickSort(j+1,right);
        }
    }
    //定位
    int Partition(int left,int right)
    {
    int i=left,j=right+1;
    do{
    do i++; while (l[i]<l[left]);
    do j--; while (l[j]>l[left]);
    if (i<j) Swap(i,j);
    }while (i<j);
    Swap(left,j);
    return j;
    }
};

int main()
{
    int num;
    cout << "请输入待排序的数组个数:";
    cin >> num;
    SortableList List(20,num);
    List.Input();
    cout << "快速排序前的结果为:";
    List.Output();
    List.QuickSort();
    cout << "快速排序后的结果为:";
    List.Output();
    return 0;
} 

实验结果:

由实验结果可得知快速排序算法成功

//寻找第k个最小元
class SortableList
{
    public:
        SortableList(int mSize,int num)
        {
            maxSize=mSize;
            l=new int[maxSize];
            n=num; //数组中已有元素个数
        }
        ~SortableList()
        {
            delete []l;
        }
        void Input()
        {
            int i;
            cout << "请输入待排序的数组:";
            for(i=0;i<n;i++)
                cin>>l[i];
        }

        void Output(int m, int index)
        {
            cout<<"第"<<m<<"个最小元是"<<l[index]<<endl;
        }
   
    int Select(int m){
        return Select(m,0,n-1,5);
    }
    
    private:
        int *l;
        int maxSize;
        int n;
    
    void Swap(int i,int j)//交换下标i、j的数组
    {
    int c=l[i];
    l[i]=l[j];
    l[j]=c;
    }
   //寻找第k小元素
    int Select(int k,int left,int right,int r) {
        int n=right-left+1;
        if(n<=r) {//若问题足够小,使用直接插入排序,取其中得第k小元素,其下标为;left+k-1
            InsertSort(left,right);
            return  left+k-1;
        }
        for(int i=1; i<=n/r; i++) {
            InsertSort(left+(i-1)*r,left+i*r-1); //二次取中规则求每组的中间值
            Swap(left+i-1,left+(i-1)*r+Ceil(r,2)-1);//将每组的中间值集中存放在子表前部
        }
        int j=Select(Ceil(n/r,2),left,left+(n/r)-1,r);//求二次中间值,其下标为j
        Swap(left,j);                                // 二次中间值为主元,并换至left处
        j=Partition(left,right);                    //对表(子表)进行分划操作
        if(k==j-left+1) return j;                    //返回第K小元素下标
        else if(k<j-left+1) return Select(k,left,j-1,r);//在左子表求第k小元素
        else return Select(k-(j-left+1),j+1,right,r);//在右子表求第k-(j-left+1)小元素
    }
    //直接插入排序算法
    void InsertSort(int left,int right) {
        for(int i=left+1; i<=right; i++) {
            int key=l[i];
            int j=i-1;
            while(j>=0 && l[j]>key) {
                l[j+1]=l[j];
                j--;
            }
            l[j+1]=key;
        }
    }
    //定位
    int Partition(int left,int right)
    {
    int i=left,j=right+1;
    do{
    do i++; while (l[i]<l[left]);
    do j--; while (l[j]>l[left]);
    if (i<j) Swap(i,j);
    }while (i<j);
    Swap(left,j);
    return j;
    }
    //划分
    int Ceil(int x,int y) {
        return x%y==0?x/y:x/y+1;
    }
};

int main()
{
    int num;
    int m;
    cout << "请输入待排序的数组个数:";
    cin >> num;
    SortableList List(20,num);
    List.Input();
    cout << "请输入所需要查找的第几个最小元:";
    cin >> m;
    int index=List.Select(m);
    List.Output(m,index);
    return 0;
}

实验结果:

由实验结果可得知寻找第k个最小元算法成功

  • 5
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值