排序

排序算法
插入排序都是默认第一个有序,所以只要进行第n-1轮,将第二个数到第n个数不断插入到先前已排好序的子集中,而选择排序也是进行n-1轮选择,但是不同的是进行第一个到第n-1个数的选择,因为最后一个必然是最大的,同样冒泡排序也是进行n-1轮交换,且从第一个数开始。
1 直接插入排序
直接插入排序思想:一列无序数首先从第一个开始逐个重新按序插入该数组中。默认第一数有序,那么从第二个数开始都与之前排好序的子集中从后往前逐一比较。这里,我们可以边比较边交换顺序,也就是未找到合适位置之前,把当前被比较的数后移一位,这个过程中后移操作是在比较过程中一步一步完成,当然也可以在比较得出插入的位置之后,然后统一后移,但这还得需要一个for循环,最后得出插入位置后,该位置因为后移操作空出来之后,即把需要插入的数插入到该位置。但要注意是为了让需要插入的记录不被移位操作覆盖了,所以在比较之前就需定义一个变量用来保存不断要插入的元素。
1:默认第一个数有序,在进行比较之前先把当前要插入的数保存下来。
2:从第二数开始和前面有序数列比较,然后比较过程中直接进行有序数列移位操作,直到找到插入位置,这时该位置上的数同样已经有上一次比较循环中后移操作空出插入位置了。
3:得到插入位置后,把记录插入,

for( i=1;i<10;i++)//i从1开始,即默认第一个数有序
    {
       int p=num[i];// ①保存插入的元素值,在后面的for移位中不被覆盖掉
       for(j=i-1;j>=0&&p<num[j];j--)//j=i-1,即从0—i-1是有序的,结束标志是找到合适的位置p<num[j],或者为最小最大j=-1结束
       {
          num[j+1]=num[j];// ②这个for循环的结束条件是找到应该插入的位置为止,
           //但要注意的是在此次比较的过程中就进行位置的移动,而不是等到找到了插入位置之后再一次性移动。后者的话比较麻烦
       }
       num[j+1]=p;// ③最后把记录插入到位置上,注意当为最大或最小时,经for循环后j=-1了
}

2希尔插入排序
希尔排序思想:缩小增量排序,在直接插入排序的基础上,前先对等长位置上的数进行排序,如5,3,1,即先隔四个数的两个数是有序的,然后隔两个数的两个数是有序的,然后最后进行最后一趟1的直接插入排序。

    for(int t=2;t>=1;t--)//t作为希尔排序的一个序列
    {
    for( i=1;i<10;i++)
    {
        int p=num[i];//保存插入的元素值,不被下面的for覆盖掉
        for(j=i-t;j>=0&&p<num[j];j-=t)
        {
            num[j+t]=num[j];//这个for循环的结束条件是找到应该插入的位置为止,
            //但要注意的是在此次比较的过程中就进行位置的移动,而不是等到找到了插入
            //位置之后再一次性移动。后者的话比较麻烦
        }
        num[j+t]=p;
    }
}

3折半插入排序
折半排序思想:采用折半查找的思想找到插入记录的位置,折半查找方法不再这赘述,然后从后往前至插入位置,所有元素统一进行移动,最后插入。

1:默认第一个数有序,备份插入记录,初始化,low=0,high=i-1,mid=(low+high)/2
2:折半查找到合适的插入位置,即为low<=high结束,当有序列的中间数大于插入记录则high=mid-1;当有序列的中间数小于插入记录,则low=mid+1;这样一直找下去即可。
3:找到插入位置之后,合适的位置为high与high+1之间,把high+1(包括)后面的的数后移,但要注意最后面的一个备份,防止移动过程中被覆盖。

    for(i=1;i<10;i++)
    {
        temp=num[i];
        int low=0,high=i-1;//将已排好序的子集作为查找对象集,第i轮排好i个数,所以min=0,high=i-1
        while(low<=high)//这里需要=,直到low大于high结束,这是折半查找的结束标志
        {
            m=(high+low)/2;
            if(num[i]<num[m])//带等于表示相等的情况按向前查找,不带等于表示相等的情况下按向后查找,带上等号则排序算法不稳定
            high=m-1;//注意这里不用m,而用m-1
            else
            low=m+1;
        }
        cout<<"low="<<low<<"&"<<"high+1="<<high+1<<endl;
        for(j=i-1;j>=high+1;j--)//找到的位置为high+1或者用low
            num[j+1]=num[j];
        num[high+1]=temp;
}

4静态循环链表的插入排序
静态链表的插入排序思想:令数组下标为0的分量作为表头,值域为max,而游标指向的是有序数列的第一个数的数组下标。然后有序序列的最后一个分量的游标指向表头的数组下标0。然后就是对游标进行插入排序,这样就省去了数组值交换的过程,而直接对游标进行一次赋值。

1初始化循环链表,把数值下标为0的分量作为表头,表头的值域为max,游标为最初的有序序列的第一个数的数组下标(即一开始下标为1的数组的下标),再把有序列最后一个数(即一开始第一个数也为最后一个数)的游标指向表头0。

2按游标有序遍历(即按游标遍历)比较找到合适插入的位置,此时游标(即前面那个数的游标,也就是指向后面的数)已经指向插入位置的后面那个,我们可以把这个游标值给插入记录的游标,即插入记录的后面一个即为他,但为了把插入位置前面一个的数的游标指向插入记录的下标,所定义一个变量来记录指向前面一个数的游标(即前两个数的游标指向前面一个数找到该分量,把他的游标修改为插入记录的游标),结束标志位从前往后比找到合适的位置slinklist[i].data>slinklist[j].data,或者知道最后一个游标j=0。
3

typedef struct slonde{
    int data;
    int next;
}slnode;
typedef struct {
    slnode size[maxsize];
    int length;
}slinklist;
slnode slinklist[maxsize];

for(i=0;i<10;i++)
    {
        slinklist[i+1].data=num[i];
    }
slinklist[0].data=max;//表头数据无用,可以看做表尾的最大值
    slinklist[0].next=1;
    slinklist[1].next=0;
    //上面是对静态链表的初始化
    for(i=2;i<=10;i++)
    {
        int p=0;//p初值为0很关键,因为在不进入for循环(即最小值时)我们把头指针的next指向该最小的,
        //而把之前头指针指向的next给现在最小值的next
        for(j=slinklist[0].next;slinklist[i].data>slinklist[j].data&&j!=0;)
        {
            p=j;
            j=slinklist[j].next;
        }
        slinklist[p].next=i;
        slinklist[i].next=j;
    }
    for(int p=slinklist[0].next;p!=0;p=slinklist[p].next)
    {
        cout<<slinklist[p].data<<"  ";
}

5选择排序
选择排序思想:进行n-1轮选择,每一轮( )选出剩下子集(从i+1到n-1)中最小的数与第i轮选择的第i位置上的数进行交换,若是当前轮选出来最小数正好在第m个位置上(子集中的第一个数)则不用交换。

for(i=0;i<10-1;i++)//n-1轮选择
{
min=num[i];
        p=i;//i为第i轮选择
        for(j=i+1;j<10;j++)
        {
            if(num[j]<min)
            {
                min=num[j];
                p=j;//p用来记录当前轮最小数的下标
            }
        }
        if(p!=i)//由于在选最小记录的下标时,会有正好当前位置,这时上面的if里面的语句没有执行
        //所以p值为上一次修改的值,若果不做处理的话,他会和上一次最小数的位置的数进行交换,这是错误的
        {
        temp=num[p];
        num[p]=num[i];
        num[i]=temp;
        }
    }

6冒泡排序
冒泡排序思想,每次比较相邻的两个数按序交换,最多交换n-1轮即可完成排序,每一轮排序都会保证前后两个数是有序的,且每一轮排序结束都会确定最后一个数的位置是正确的,下一轮排序不需要参加交换。第一轮比较的次数为n-1次,第二轮比较的次数为n-2次,即第j轮比较的次数为n-j-1次,j从0开始。

    int flag=0;//结束标志
    int sum;//统计交换的次数
int temp;//交换操作时的临时存储变量
    for(j=0; j<9&&flag==0; j++)//最坏的情况是n-1次,当然也可以设置标志,
    //如果里有一轮内层for循环没有执行if也可以作为结束标志
    {
        flag=1;
        for(i=0; i<9-j; i++)//i<n-1-j是因为后j个数以按最终序排列好了
        {
            if(num[i]>num[i+1])
            {
                flag=0;
                temp=num[i+1];
                num[i+1]=num[i];
                num[i]=temp;
            }
            sum++;
        }
    }

7快速排序
8归并排序
9堆排序
堆排序思想:考虑到选择排序每次比较都需要在剩下的n-m+1个数比较n-m次选出当前最小数,比较次数较多,如果每次把上一次比较的信息记录下来,考虑其中的传递性,可以节省比较次数。

堆排序采用完全二叉树的结构,每次筛选出最值放到根节点位置,筛选的机制是保证每棵树的根节点的值不小于(或不大于)左右子树。选完一次之后,把最上面的根节点拿出来,放到当前位置,然后

1:为无序列建立一个堆,这里就是要保证 ,具体实现是这样的

按下标编号建立一颗完全二叉树,一棵树的根节点数等于总节点数一半,为了保证 ,从最下面的第一层编号最大的根节点开始和他的左右叶子结点比较,是否符合 ,每次从 中选出需要的最值,然后和 比较,并交换位置,在把上一个根节点换下来后,再进行和当前的左右子树进行堆调整。

2:在输出堆顶元素后,调整剩余元素成为一个新堆。同要是要保证 。
具体实现,先把数列最后一个元素填补堆顶

/**
排序算法:1插入排序
**/
/*
#include <iostream>
using namespace std;
int main()
{
    int num[10]={2,5,6,3,4,1,3,5,2,7};
    int i,j;
    for( i=1;i<10;i++)//i从1开始,即默认第一个数有序
    {
        int p=num[i];//保存插入的元素值,在后面的for移位中不被覆盖掉
        for(j=i-1;j>=0&&p<num[j];j--)//j=i-1,即从0—i-1是有序的,结束标志是找到合适的位置p<num[j],或者为最小最大j=-1结束
        {
            num[j+1]=num[j];//这个for循环的结束条件是找到应该插入的位置为止,
            //但要注意的是在此次比较的过程中就进行位置的移动,而不是等到找到了插入位置之后再一次性移动。后者的话比较麻烦
        }
        num[j+1]=p;//最后把记录插入到位置上,注意当为最大或最小时,经for循环后j=-1了
    }
    for(int p=0;p<10;p++)
    cout<<num[p]<<"  ";
    return 0;
}
*/
/***
2希尔排序
*/
/*
#include <iostream>
using namespace std;
#define maxsize 100
int main()
{
    int num[10]={2,5,6,3,4,1,3,5,9,7};
    int i,j;
    for(int t=2;t>=1;t--)//t作为希尔排序的一个序列
    {
    for( i=1;i<10;i++)
    {
        int p=num[i];//保存插入的元素值,不被下面的for覆盖掉
        for(j=i-t;j>=0&&p<num[j];j-=t)
        {
            num[j+t]=num[j];//这个for循环的结束条件是找到应该插入的位置为止,
            //但要注意的是在此次比较的过程中就进行位置的移动,而不是等到找到了插入
            //位置之后再一次性移动。后者的话比较麻烦
        }
        num[j+t]=p;
    }
    }
    for(int p=0;p<10;p++)
    cout<<num[p]<<",";
    return 0;
}
*/
/**
3折半插入排序

*/
/*
#include <iostream>
using namespace std;
int main()
{
    int num[10]={2,5,3,3,4,1,3,5,9,7};
    int i,j,m;
    int temp;
    for(i=1;i<10;i++)
    {
        temp=num[i];
        int low=0,high=i-1;//将已排好序的子集作为查找对象集,第i轮排好i个数,所以min=0,high=i-1
        while(low<=high)//这里需要=,直到low大于high结束,这是折半查找的结束标志
        {
            m=(high+low)/2;
            if(num[i]<=num[m])//带等于表示相等的情况按向前查找,不带等于表示相等的情况下按向后查找
            high=m-1;//注意这里不用m,而用m-1
            else
            low=m+1;
        }
        cout<<"low="<<low<<"&"<<"high+1="<<high+1<<endl;
        for(j=i-1;j>=high+1;j--)//找到的位置为high+1或者用low
            num[j+1]=num[j];
        num[high+1]=temp;
    }
    for(int p=0;p<10;p++)
    cout<<num[p]<<"   ";
}
*/
/**
4静态链表的插入排序
**/
/*
#include <iostream>
using namespace std;
#define maxsize 100

//定义静态链表的方式
/*typedef struct{
    int data;
    int next;
}slnode;
typedef struct {
    slnode size[maxsize];
    int length;
}slinklist;
*/
/*
typedef struct slnode{
    int data;
    int next;
}slnode;

slnode slinklist[maxsize];
int main()
{
    int num[10]={2,5,6,3,4,1,3,5,9,7};
    int i,j;
    for(i=0;i<10;i++)
    {
        slinklist[i+1].data=num[i];
    }
    slinklist[0].data=0;
    slinklist[0].next=1;
    slinklist[1].next=0;
    //上面是对静态链表的初始化
    for(i=2;i<=10;i++)
    {
        int p=0;//p初值为0很关键,因为在不进入for循环(即最小值时)我们把头指针的next指向该最小的,
        //而把之前头指针指向的next给现在最小值的next
        for(j=slinklist[0].next;slinklist[i].data>slinklist[j].data&&j!=0;)
        {
            p=j;
            j=slinklist[j].next;
        }
        slinklist[p].next=i;
        slinklist[i].next=j;
    }
    for(int p=slinklist[0].next;p!=0;p=slinklist[p].next)
    {
        cout<<slinklist[p].data<<"  ";
    }
    cout<<endl;
    for(int p=0;p<=10;p++)
    {
        cout<<slinklist[p].data<<"  ";
    }
    cout<<endl;
    for(int p=0;p<=10;p++)
    {
        cout<<slinklist[p].next<<"  ";
    }
    cout<<endl;
    int p=slinklist[0].next,q=0;
    //cout<<p<<endl;
    for(i=1;i<10;i++)
    {
        cout<<"rrrrrrrrp="<<p<<",i="<<i<<",q="<<q<<endl;
        while(p<i)
        {
            p=slinklist[p].next;
            //cout<<"rrrrrr"<<endl;
            cout<<"p="<<p<<",i="<<i<<",q="<<q<<endl;
        }
       q=slinklist[p].next;
        if(p!=i)
        {
            int temp1=slinklist[p].data;
            slinklist[p].data=slinklist[i].data;
            slinklist[i].data=temp1;

            int temp2=slinklist[p].next;
            slinklist[p].next=slinklist[i].next;
            slinklist[i].next=temp2;

            slinklist[i].next=p;
        }
        p=q;
        //cout<<slinklist[i].data;
    }
    for(int i=1;i<=10;i++)
    cout<<slinklist[i].data<<"  ";
}
*/
/**

5选择排序
**/
/*
#include <iostream>
using namespace std;
int main()
{
    int num[10]= {2,5,6,3,4,1,3,5,9,7};
    int i,j;
    int min;//记录最小值
    int temp;//交换位置时的一个临时变量
    int p;//记录当前要排序数的下标
    for(i=0;i<10-1;i++)//n-1轮选择
    {
        min=num[i];
        p=i;//i为第i轮选择
        for(j=i+1;j<10;j++)
        {
            if(num[j]<min)
            {
                min=num[j];
                p=j;//p用来记录当前轮最小数的下标
            }
        }
        if(p!=i)//由于在选最小记录的下标时,会有正好当前位置,这时上面的if里面的语句没有执行
        //所以p值为上一次修改的值,若果不做处理的话,他会和上一次最小数的位置的数进行交换,这是错误的
        {
        temp=num[p];
        num[p]=num[i];
        num[i]=temp;
        }
    }
    for(int i=0; i<10; i++)
    {
        cout<<num[i]<<"  ";
    }
}
*/
/***
6冒泡排序
**/
/*
#include <iostream>
using namespace std;
#define maxsize 100
int main()
{
    int num[10]= {2,5,6,3,4,1,3,5,9,7};
    int i,j;
    int flag=0;
    int sum=0;
    int temp=0;
    for(j=0; j<9&&flag==0; j++)//最坏的情况是n-1次,当然也可以设置标志,
    //如果里有一轮内层for循环没有执行if也可以作为结束标志
    {
        flag=1;
        for(i=0; i<9-j; i++)//i<9-j是因为后j个数以按最终序排列好了
        {
            if(num[i]>num[i+1])
            {
                flag=0;
                temp=num[i+1];
                num[i+1]=num[i];
                num[i]=temp;
                sum++;
            }
        }
    }
    for(int i=0; i<10; i++)
    {
        cout<<num[i]<<"  ";
    }
    cout<<sum<<endl;
}
*/
/**
7快速排序
**/
/*
#include <iostream>
using namespace std;
#define maxsize 100
int partion(int *num,int low,int high)
{
    int key=num[low];
    while(low<high)
    {
        while(low<high&&num[high]>=key)--high;
        {
            int temp=num[low];
            num[low]=num[high];
            num[high]=temp;
        }
        while(low<high&&num[low]<=key)++low;
        {
            int temp=num[low];
            num[low]=num[high];
            num[high]=temp;
        }
    }
    return low;
}
void qsort(int *num,int low,int high)
{
    if(low<high)
    {
        int p=partion(num,low,high);
        qsort(num,low,p-1);
        qsort(num,p+1,high);
    }

}
int main()
{
    int num[10]= {2,5,6,3,4,1,3,5,9,7};
    qsort(num,0,9);
    for(int i=0; i<10; i++)
    {
        cout<<num[i]<<"  ";
    }
}
*/
/**

8归并排序
**/


/**

9堆排序
**/

/*#include <iostream>
using namespace std;
void merge(int *num,int *num2,int i,int m,int n)
{
    int j,k;
    for(j=m+1,k=i;i<=m&&j<=n;k++)
    {
        if(num[i]<num[j])
        num[k]=num[i++];
        else
        num[k]=num[j++];
    }
    if(i<=m)
    {
        for(;i<=m;)
        num[k++]=num[i++];
    }
    if(j<=n)
    {
        for(;j<=n;)
        num[k++]=num[j++];
    }
}
void msort(int *num,int *num2,int s,int t)
{
    int m=0;
    int num3[10]={0};
    if(s==t) num2[s]=num[s];
    else
    {
        m=(s+t)/2;
        msort(num,num3,s,m);
        msort(num,num3,m+1,t);
        merge(num3,num2,s,m,t);
    }
}
void mergesort(int *num)
{
    int length=10;
    msort(num,num,0,length-1);
}
int main()
{
    int num[10]= {2,5,6,3,4,1,3,5,9,7};
    mergesort(num);
      for(int i=0; i<10; i++)
    {
        cout<<num[i]<<"  ";
    }
}
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值