排序(快速排序、shell排序、树形选择排序、堆排序、链式基数排序)(C++实现)

一、实验要求

(1) 采用不同实验数据来观察快速排序的实验中比较和交换元素的次数,并分析数据的规模和初始特性与比较与交换次数之间的函数关系。

测试数据要求:至少5组以上;每组数据规模不小于100。

 

(2) 完成下面功能:将一个整型数组调整为这样的数组:所有3的倍数在最左边,所有除以3余1的数在中间,而所有除以3余2的数在最右边。要求算法的时间尽可能少。  

测试数据:数组元素分别为:

第一组数据:

(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26)

第二组数据: 

(11,12,13,14,15,1,2,3,4,5,6, 10, 16, 1,22,23,2,17,18,19,20,24, 7,8,9,25,26)

第三组数据: 

(5,6,7, 1,2,3,4,8,9,10,11,12,13, 16,17,18, 14, 25,26,15,19,20,21,22,23,24)

 

(3) 实现shell排序算法,并观察在采用不同的步长选取方法对排序过程中数据的比较和移动次数的影响。

测试数据:

数组元素分别为:

第一组数据:

(180,203,32,46,25,76,17,58,99,100,11,102,13,54,75,6,27,18,19,29,2,82)

其余数据的规模应不少于第一组数。

(4) 设计算法实现树形选择排序,要求能用数组和树来演示排序过程,以清晰地表示出排序过程。 

测试数据:

数组元素分别为:

第一组数据:

(106,213,325,446,579,654,721,870,917,510,21,632,73,14,815,316,412,18,619,720,21,808,923,25,26 )

 

(5) 以数组和二叉树形式动态演示堆排序算法的排序过程。 

测试数据:

数组元素分别为:

第一组数据:

(106,213,325,446,579,654,721,870,917,510,21,632,73,14,815,316,412,18,619,720,21,808,923,25,26)

 

(6)* 按链式基数排序的方法实现对整数表(假设每个元素最多为三位)的排序。

测试数据:

数组元素分别为:   

第一组数据:

( 106,213,325,446,579,654,721,870,917,510,21,632,73,14,815,316,412,18,619,720,21,808,923,25,26  )   

其余数据的规模应不少于第一组数的两倍。

二、算法设计

由于快速排序、希尔排序、堆排序书中算法思想已详细给出故不再赘述

       第2题算法思想:借用快速排序分区思想,分两步完成,第一步先将余数为 0 的元素与其他情况进行二分划分,即余数为 0 元素存入左边子表,余数为 1 和 2 的元素存在表的右端;第二部再将右端子表按余数 1 和 2 进行二分划分即可。第一步:从左端找到第一个余数不为 0(余数为 1 或 2)的元素,存入临时单元 A[];以下步骤循环执行,直到 low==high:从高端找到一个余数为 0 的元素,存入 A[low];从左端找到一个余数不为 0 的元素,存入 A[high];循环结束后,low==high,在此位置存入 A[0]元素,即:A[low]=A[0],或 A[high]上面处理结束后,余数为 0 的元素存入表的左端,右端为余数为 1 或 2 的元素,且 A[low]为右端子表的第一个元素。接下来再将右子表 A[low...n],按余数为 1 和 2 进行二分划分,此时,low 数值不变,high 重新初始化为 n。

       第5题树形选择排序算法思想:树形选择排序(Tree Selection Sort),又称锦标赛排序(Tournament Sort),是一种按照锦标赛思想进行选择排序的方法。首先对n个记录的关键字进行两两比较,然后在其中[n/2](向上取整)个较小者之间再进行两两比较,如此重复,直至选出最小关键字的记录为止。

        第6题链式基数排序算法思想:基数排序也称作桶排序。设待排序的元素是3位10进制整(不足3位的关键字在高位补0),设置10个桶,令其编号分别为0,1,2…9。首先元素最低位的数值一次把各个元素放到相应的桶中。然后按照桶号从小到大和进入桶中数据元素的先后次序收集分配在各个桶中的数据元素。这样就形成了数据元素集合的一个新的排列,称这样的一次排序过程为一次基数排序。再对一次基数排序得到的数据元素按关键字次低位的数值依次把各个数据元素放到相应的桶中,按照桶号从小到大和进入桶中数据元素的先后次序收集分配在各桶中的数据元素,这样的过程重复进行。当完成了3次基数排序后,就得到了排好序的数据元素序列

三、代码实现

#ifndef _SORT_H_
#define _SORT_H_
#include <iostream>
#include <cmath>
using namespace std;

 typedef struct Node{
    int data;   //数据域
    int index;  //数据的索引
    int flag;   //标记是否被淘汰,0表示被淘汰
 }node;
 //菜单
 void menu()
 {
     cout<<"********************************************"<<endl;
     cout<<"0退出程序"<<endl;
     cout<<"1快速排序"<<endl;
     cout<<"2整型数组调整为3的倍数在最左边,所有除以3余1的数在中间,而所有除以3余2的数在最右边"<<endl;
     cout<<"3希尔排序"<<endl;
     cout<<"4树形选择排序"<<endl;
     cout<<"5以二叉树形式动态演示堆排序算法的排序过程"<<endl;
     cout<<"6*链式基数排序对整数(最多为三位)的排序"<<endl;
     cout<<"********************************************"<<endl;
     cout<<"请输入执行序号:";
 }
 //树形输出
 void treePrint(node *&tree,int num)
 {
     int n,i,j,t,q,s,p,m=0,k=0;
    n=(int)((log(num)/log(2))+1);
    p=n;
    for(i=0;i<n;i++)
    {
        k=pow(2,m)+k;
        t=pow(2,m);
        j=pow(2,p-1)-1;
        q=pow(2,p)-1;
        s=q;
        for(j;j>0;j--)
        {
            cout<<" ";
        }
        for(t;t<=k;t++)
        {
            if(tree[t].flag==0)
            {
                cout<<"*";
                for(q;q>0;q--)
                cout<<" ";
                q=s;
            }
            else{
                cout<<tree[t].data;
                for(q;q>0;q--)
                cout<<" ";
                q=s;
            }
        }
        m++;
        p--;
        j=n-i-1;
        cout<<endl;
    }
 }
 //树形输出
 template<class ElementType>
 void treePrint(ElementType A[],int num)
 {
     int n,i,j,t,q,s,p,m=0,k=0;
    n=(int)((log(num)/log(2))+1);
    p=n;
    for(i=0;i<n;i++)        //按层次输出
    {
        k=pow(2,m)+k;
        t=pow(2,m);
        j=pow(2,p-1)-1;
        q=pow(2,p)-1;
        s=q;
        for(j;j>0;j--)      //输出空格
        {
            cout<<" ";
        }
        for(t;t<=k;t++)
        {
            if(t>num)
            {
                cout<<"*";
                for(q;q>0;q--)
                cout<<" ";
                q=s;
            }
            else{
                cout<<A[t];
                for(q;q>0;q--)
                cout<<" ";
                q=s;
            }
        }
        m++;
        p--;
        j=n-i-1;
        cout<<endl;
    }
 }
 //调整树
 void adjustTree(node *&tree,int pos)
 {
     int i=pos;
     if(i%2)  //i位于右子树
     {
         tree[i/2]=tree[i-1];
     }
     else{
         tree[i/2]=tree[i+1];
     }
     i/=2;  //求其父节点下标
     int j;
     //上升到根节点停止循环
     while(i)
     {
         i%2?j=i-1:j=i+1;       //寻找左兄弟或右兄弟
         if(!tree[i].flag||!tree[j].flag) //有一个已淘汰
         {
             if(tree[i].flag)
             {
                 tree[i/2]=tree[i];
             }
             else{
                 tree[i/2]=tree[j];
             }
         }
         else{          //都没有淘汰
            if(tree[i].data>tree[j].data)
            {
                tree[i/2]=tree[j];
            }
            else{
                tree[i/2]=tree[i];
            }
         }
         i/=2;      //返回到上一层
     }
 }
//树形选择排序
template<class ElementType>
void treeSelectSort(ElementType *A,int n)
{
    int height=1;                   //height保存树的高度
    while(pow(2,height-1)<n)
    {
        height++;
    }
    int leafNum=pow(2,height-1);   //叶子数目
    int nodeNum=2*leafNum-1;      //nodeNum保存节点数目
    node * tree=new node[nodeNum]; //顺序存储一棵树
    //为树的叶子节点赋值
    int i=0;
    while(i<leafNum)
    {
        if(i<n)
        {
            tree[i+leafNum].data=A[i];  //tree数组第一个元素不存入有效元素
            tree[i+leafNum].index=i;  //索引从1开始
            tree[i+leafNum].flag=1;
        }
        else{
            tree[i+leafNum].flag=0;  //叶子节点的无效元素被淘汰
        }
        i++;
    }
    //初始调整树
    i=leafNum;      //最后一层第一个叶子节点下标
    int j;
    while(i!=1)
    {
        j=i;
        while(j<2*i) //最后一层最后一个叶子节点下标
        {
            //两个节点比较,其最小值赋值给父节点
            if(!tree[j+1].flag||tree[j+1].data>tree[j].data)
            {
                tree[j/2]=tree[j];
            }
            else{
                tree[j/2]=tree[j+1];
            }
            j+=2;  //一次两两比较
        }
        i/=2;      //返回上一层
    }
    //非初次调整,确定剩下的n-1个节点的次序
    i=0;
    while(i<n-1)
    {
        A[i]=tree[1].data;
        treePrint(tree,nodeNum);  //输出树形
        cout<<endl;
        //此处添加调整函数
        tree[leafNum+tree[1].index].flag=0;     //根节点依次被淘汰
        adjustTree(tree,leafNum+tree[1].index);
        i++;
    }
    treePrint(tree,nodeNum);
    cout<<endl;
    A[n-1]=tree[1].data;
    delete [] tree;
}
//快速排序
template<class ElementType>
void partition(ElementType A[],int start,int end,int &sign,int &compare,int &change)
{
    ElementType x;
    int s,e;
    s=start;
    e=end;
    x=A[start];
    while(s!=e)
    {
        //在数组末端寻找小元素下标
        while(s<e && A[e]>x)
        {
            e--;
            compare++;
        }
        //找到之后赋值给A[s]
        if(s<e)
        {
            A[s]=A[e];
            s+=1;
            change++;
        }
        //在数组始端找到大元素移到数组末端
        while(s<e && A[s]<x)
        {
            s++;
            compare++;
        }
        //找到之后赋值给A[e]
        if(s<e)
        {
            A[e]=A[s];
            e-=1;
            change++;
        }
    }
    A[s]=x;         //找到位置
    sign=s;         //返回标志位
    change++;
}
//递归实现排序
template<class ElementType>
void quickSort(ElementType A[],int start,int end,int &compare,int &change)
{
    int i;
    if(start<end)
    {
        partition(A,start,end,i,compare,change);
        quickSort(A,start,i-1,compare,change);
        quickSort(A,i+1,end,compare,change);
    }
}
//整型数组调整为3的倍数在最左边,所有除以3余1的数在中间,而所有除以3余2的数在最右边
template<class ElementType>
void devideArray(ElementType A[],int n)
{
    int low=1;
    int high=n;    //数组最后元素下标
    //从下标为0开始的元素,搜索到其余数不为0的元素下标
    while(low<high&&A[low]%3==0)
    {
        low++;
    }
    A[0]=A[low];
    while(low<high)
    {
        //从下标为end中选取元素除3余数为0的元素赋值到A[start]中
        while(low<high&&A[high]%3!=0)
        {
            high--;
        }
        A[low]=A[high];
       // low++;
        //选取除3余数为不为0元素赋值给A[high]
        while(low<high&&A[low]%3==0)
        {
            low++;
        }
        A[high]=A[low];
      //  high--;
    }
    A[low]=A[0];    //把第一个余数不为0的元素赋值给A[low]
    //余数为1,2在进行划分
    high=n;
    //从下标为low开始的元素,搜索到其余数不为1的元素下标
    while(low<high&&A[low]%3==1)
    {
        low++;
    }
    A[0]=A[low];
    while(low<high)
    {
        //从下标为end中选取元素除3余数为1的元素赋值到A[start]中
        while(low<high&&A[high]%3!=1)
        {
            high--;
        }
        A[low]=A[high];
     //   low++;
        //选取除3余数为不为0元素赋值给A[high]
        while(low<high&&A[low]%3==1)
        {
            low++;
        }
        A[high]=A[low];
      //  high--;
    }
    A[low]=A[0];    //把第一个余数不为1的元素赋值给A[low]
}
//希尔排序
template<class ElementType>
void shellSort(ElementType A[],int n)
{
    int i,j,count=0;
    ElementType temp;
    int dh=n/2;
    while(dh>=1)
    {
        count=0;
        cout<<"步长为:"<<dh<<endl;
        for(i=dh+1;i<=n;i++)
        {
            temp=A[i];
            j=i;
            while(j>dh&&temp<A[j-dh])
            {
                A[j]=A[j-dh];
                j-=dh;
                count++;
            }
            A[j]=temp;
        }
        cout<<"移动次数为:"<<count<<endl;
        dh/=2;
    }
}
//筛选算法
template<class ElementType>
void sift(ElementType A[],int k,int m)
//k是根节点的下标,m是数组中最后一个元素
{
    int i,j;
    bool finished=false;
    ElementType x;
    x=A[k];
    i=k;
    j=2*i;
    while(j<=m&&!finished)  //确定i节点不是叶子节点且搜索结束
    {
        if(j<m&&A[j]<A[j+1])
            j+=1;   //j指向左右孩子中的最大者
        if(x>=A[j])
            finished=true;
        else{
            A[i]=A[j];
            i=j;
            j=2*j;
        }
    }
    A[i]=x;
}
//堆排序
template<class ElementType>
void heapSort(ElementType A[],int n)
{
    int i;
    ElementType temp;
    for(i=n/2;i>=1;i--)
    {
        sift(A,i,n);    //建初堆
    }
    treePrint(A,n);
    cout<<endl;
    for(i=n;i>=2;i--)
    {
        temp=A[i];
        A[i]=A[1];      //A[i]与A[1]交换
        A[1]=temp;
        sift(A,1,i-1);  //重新筛选
        treePrint(A,i-1);
        cout<<endl;
    }
}
#endif // _SORT_H_
#ifndef _RADIXSORT_H_
#define _RADIXSORT_H_
#include <iostream>

using namespace std;

typedef  int ElementType ;
typedef struct lNode{
    ElementType data;
    struct lNode * next;
}lnode;

//初始化数组
void initArray(lnode * b[10][2],int flag[])
{
    int i=0,j=0;
    for(i=0;i<10;i++)
        for(j=0;j<2;j++)
            b[i][j]=0;
    for(i=0;i<10;i++)
        flag[i]=0;
}
//插入节点
void insertNode(lnode * b[10][2],int flag[],int i,int x)
{
    if(flag[i]==0)      //建立首节点
    {
        lnode *L=new lnode;       //首节点指针
        L->data=x;
        L->next=NULL;
        b[i][0]=L;  //首节点指针
        b[i][1]=L;  //尾指针
        flag[i]++;
    }
    else{
        lnode *L=new lnode;
        L->data=x;
        L->next=NULL;
        b[i][1]->next=L;
        b[i][1]=L;      //更新尾结点指针
    }
}
//连接链表
void link(lnode * b[10][2],lnode *&H,lnode *&R)
{
    int i=0;
    while(b[i][0]==0)
    {
        i++;
        if(i==10)
            return;
    }
    H=b[i][0];  //获取头指针
    R=b[i][1];  //获取尾指针
    i++;
    for(i;i<10;i++)
    {
        while(b[i][0]==0)
        {
            i++;
            if(i==10)
                return;
        }
        R->next=b[i][0];  //尾结点指向下一组的头指针
        R=b[i][1];       //更新尾结点指针
    }
}
//插入节点
void linkNode(lnode * b[10][2],int flag[],int i,lnode *& p)
{
    if(flag[i]==0)      //建立首节点
    {
        b[i][0]=p;  //首节点指针
        b[i][1]=p;  //尾指针
        p->next=NULL;
        flag[i]++;
    }
    else{
        b[i][1]->next=p;
        b[i][1]=p;      //更新尾结点指针
        p->next=NULL;
    }
}
//基数排序
void radixSort(int A[],int n,lnode * b[10][2])
{
    int x,i=0;
    int flag[10]={0};
    lnode *H=NULL,*R=NULL;
    for(i;i<n;i++)   //对个位数进行分配(连接)
    {
        x=A[i]%10;
        switch(x)
        {
            case 0:
                insertNode(b,flag,0,A[i]);
            break;
            case 1:
                insertNode(b,flag,1,A[i]);
            break;
            case 2:
                insertNode(b,flag,2,A[i]);
            break;
            case 3:
                insertNode(b,flag,3,A[i]);
            break;
            case 4:
                insertNode(b,flag,4,A[i]);
            break;
            case 5:
                insertNode(b,flag,5,A[i]);
            break;
            case 6:
                insertNode(b,flag,6,A[i]);
            break;
            case 7:
                insertNode(b,flag,7,A[i]);
            break;
            case 8:
                insertNode(b,flag,8,A[i]);
            break;
            case 9:
                insertNode(b,flag,9,A[i]);
            break;
        }
    }
    //将多个链合成一个链
    link(b,H,R);
    initArray(b,flag);
    lnode *p,*q;
    cout<<"个位数排列所得序列为;";
    //输出数据
    p=H;
    while(p)
    {
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
    p=H;
    //对十位数进行分配
    while(p)
    {
        q=p->next;
        x=(p->data)/10%10;
        switch(x)
        {
            case 0:
                linkNode(b,flag,0,p);
            break;
            case 1:
                linkNode(b,flag,1,p);
            break;
            case 2:
                linkNode(b,flag,2,p);
            break;
            case 3:
                linkNode(b,flag,3,p);
            break;
            case 4:
                linkNode(b,flag,4,p);
            break;
            case 5:
                linkNode(b,flag,5,p);
            break;
            case 6:
                linkNode(b,flag,6,p);
            break;
            case 7:
                linkNode(b,flag,7,p);
            break;
            case 8:
                linkNode(b,flag,8,p);
            break;
            case 9:
                linkNode(b,flag,9,p);
            break;
        }
        p=q;
    }
    //将多个链合成一个链
    link(b,H,R);
    initArray(b,flag);
    cout<<"十位数排列所得序列为;";
    //输出数据
    p=H;
    while(p)
    {
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
    p=H;
    //对百位数进行分配
    while(p)
    {
        q=p->next;
        x=(p->data)/10/10%10;
        switch(x)
        {
            case 0:
                linkNode(b,flag,0,p);
            break;
            case 1:
                linkNode(b,flag,1,p);
            break;
            case 2:
                linkNode(b,flag,2,p);
            break;
            case 3:
                linkNode(b,flag,3,p);
            break;
            case 4:
                linkNode(b,flag,4,p);
            break;
            case 5:
                linkNode(b,flag,5,p);
            break;
            case 6:
                linkNode(b,flag,6,p);
            break;
            case 7:
                linkNode(b,flag,7,p);
            break;
            case 8:
                linkNode(b,flag,8,p);
            break;
            case 9:
                linkNode(b,flag,9,p);
            break;
        }
        p=q;
    }
    //将多个链合成一个链
    link(b,H,R);
    initArray(b,flag);
    cout<<"百位数排列所得序列为;";
    //输出数据
    p=H;
    while(p)
    {
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
    //销毁链表
    p=H;
    while(p)
    {
        q=p->next;
        delete p;
        p=q;
    }
}
#endif // _RADIXSORT_H_
#include <iostream>
#include <Cstdlib>
#include "sort.h"
#include <ctime>
#include "radixSort.h"

using namespace std;

//为数组赋值
void assignment(int a[],int &n,int flag)
{
    int x,i;
    n=0;
    cout<<"请依次输入数值(按-9999结束):";
    cin>>x;
    if(flag==0)
    {
        i=0;
    }
    else{
        i=1;
    }
    while(x!=-9999)
    {
        a[i]=x;
        i++;
        n++;
        cout<<"请输入数值:";
        cin>>x;
    }
}
//数组随机赋值
void randomAssignment(int a[],int &n,int flag)
{
    int x,i;
    srand(time(NULL));
    if(flag==0)
    {
        i=0;
        n=n-1;
    }
    else{
        i=1;
    }
    for(i;i<=n;i++)
    {
        x=rand()%1000;
        a[i]=x;
    }
}
//输出数组
void print(int a[],int n,int flag)
{
    int i;
    if(flag==0)
    {
        i=0;
        n=n-1;
    }
    else{
        i=1;
    }
    for(i;i<=n;i++)
        cout<<a[i]<<" ";
}
int main()
{
    int x,i=0,n=0;
    int compare=0,change=0; //比较次数和交换次数
    int a[1000]={0};
    lnode * b[10][2]={0};
    menu();
    cin>>x;
    while(x!=0)
    {
        switch(x)
        {
            case 1:
                n=100;
                for(n;n<=300;n+=50)
                {
                    randomAssignment(a,n,0);
                    quickSort(a,0,n,compare,change);
                    cout<<endl;
                    cout<<"元素个数为:"<<n<<endl;
                    cout<<"比较次数为:"<<compare<<endl;
                    cout<<"交换次数为:"<<change<<endl;
                    print(a,n,0);
                }
                cout<<endl;
            break;
            case 2:
                assignment(a,n,1);
                devideArray(a,n);
                print(a,n,1);
                cout<<endl;
            break;
            case 3:
                n=100;
                randomAssignment(a,n,1);
                shellSort(a,n);
                print(a,n,1);
                cout<<endl;
            break;
            case 4:
                assignment(a,n,0);
                treeSelectSort(a,n);
                print(a,n,0);
                cout<<endl;
            break;
            case 5:
                assignment(a,n,1);
                heapSort(a,n);
                print(a,n,1);
                cout<<endl;
            break;
             case 6:
                assignment(a,n,0);
                radixSort(a,n,b);
            break;
        }
        system("PAUSE");
        system("CLS");
        menu();
        cin>>x;
    }
    return 0;
}

四、实验截图

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值