排序方法(一)

参考

        参考

冒泡排序

原理

        比较相邻两个元素的大小,进行调整位置。

代码

        略。

快速排序

原理

        通过一次排序将数据分成两个独立的部分,再分别对两部分进行排序,直到结束。

代码

void quicksort(int a[],int left,int right){
    if(right <= left){
        return;
    }
    int i = right,j = left;
    int base = a[j];
    while(i > j){
        //开始从右往左寻找,寻找第一个比base小的数
        while (i > j && a[i] >= base) {
            i--;
        }
        //从左往右寻找,寻找第一个比base大的数,同时不能寻出右指针的位置
        while (i > j && a[j] <= base) {
            j++;
        }
        if(i > j){//如果各自寻找,交换两者位置
            swap(a, j, i);
        }
    }
    if(j == i){//两者重逢,交换重逢位置与基数
        swap(a, left, j);
        quicksort(a, left, j-1);//对左右两个数组进行快速排序
        quicksort(a, j+1, right);
    }
}
        有一点需要说明:上例是从小往大排序的,所以必须先从右往左开始寻找,内部的两个循环的顺序不能交换如果从大往小排序,则两个循环的顺序必须换过来。假如对10,0,11进行从小往大排序,并且交换两个循环的位置,那么i = j时两者都指向的了11,然后将10与11进行交换,很明显不符合排序要求。

堆排序

原理

        先将数据排列成一个大顶堆或小顶堆,然后将根结点与最后一个交换,这样就将最大数或最小数放到了数组的末位。依次进行,走到排完整个数组即可。

        堆是一个完全二叉树,序号为k的节点的左右子节点的序号为2k,2k+1。

代码

//调整i元素的位置,以确保生成的堆是最小堆
void siftdown(int h[],int i,int n){
    int pos = i;
    while(i*2 <= n){//有左子树
        int root = h[i];
        if(root < h[2*i]){//比左子树值小
            pos = i;
        }else{//比左子树的值大,但也不需要现在交换位置,因为可能右子树的值更小
            pos = 2*i;
        }
        if(2*i+1<=n){//有右子树
            if(h[2*i+1] < h[pos]){//右子树的值更小
                pos = 2*i + 1;
            }
        }
        if(pos != i){//需要调整位置
            swap(h, pos, i);
            i = pos;//判断调整到新位置后,要不是仍旧需要调整
        }else{//不需要调整位置,所以结束循环
            break;
        }
    }
}
        上面方法只是对某个位置的元素进行调整,以使其符合最小堆的要求。故而只要使用一个循环,将所有的元素都进行调整即可。

        这里还应该意识到,所有的叶子节点是不用进行往下调整的,因为它没有子节点。故而循环开始的位置应该是最后一个叶子结点的父结点。

        在循环过程中,会采用从后往前,这是因为如果从根结点开始的话,并不能保证新调整到根节点上的元素是最小元素(因为还有很多元素没有进行比较)。代码如下:

int main(int argc, const char * argv[]) {
    int num = 9;
    int a[] = {0,10,1,100,20,4,354,43,18,0};//注意a[0]不用
    int x = 0;
    for(x = num /2;x>=1;x--){
        siftdown(a, x,num);//先将数组构成小顶堆
    }
    while(num >= 1){
        printf("%d ",a[1]);//输出最小的.也可将该值存储起来,
        a[1] = a[num];
        num--;
        siftdown(a, 1,num);//将最后一个值移动到第一个位置后,需要判断该位置是否需要再进行调整
    }
}

选择排序

原理

        先找到序列中最小值(或最大值)于序列中的第一个元素交换,这样就将最大值或最小值放到了最前面;再从剩余部分(除了第一个元素之外的部分)中找到最大(小)值与第二个元素交换,依次类推,直到序列结束。

        选择排序即是选择最大或最小的元素按放在已排序完成的队列的末尾。

代码

void selectsort(int a[],int count){
    int x = 1;
    for (x =1; x<=count; x++) {
        int index = x;
        int j = x+1;
        for(;j<=count;j++){//从当前元素的下一个元素进行遍历
            if(a[j] < a[index]){//如果有比当前还小的,则记录位置
                index = j;
            }
        }
        if(index != x){//最小的不是当前元素,所以把当前元素与最小的元素进行交换
            swap(a, x, index);
        }
    }
}

插入排序

原理

        将序列分为已排序(初始时只有序列的第一个元素)与未排序两部分,取未排序的第一个元素与已排序的最后一个元素比较,如果前者小,则将前者往前移(即将未排序的首位的值换成已排序的末尾值);再与已排序的倒数第二个进行比较,如果前者小,则将已排序的末尾值设置成已排序的倒数第二位值。依次类推,直到找到比未排序的首位小的位置或者已排序序列的首位。

        经上面操作后,就将未排序的首位放入到了已排序中的合适位置。然后进行下一个循环即可。

代码

void insertsort(int a[],int count){
    int x = 1;
    for(x  = 0;x< count-1;x++){
        int j = x+1;
        int value = a[j];
        while(value < a[j - 1] && j>0){
            a[j] = a[j-1];//用前一位的值为后一位赋值,就相当于把数值整体往后移了一位。而多余的空位就是用来插入value的。
            j--;//j始终指向的是当前value要插入的位置的下标
        }
        a[j] = value;
    }
}

归并排序

原理

        将序列沿中间坐标分为两组,分别对两种进行归并排序,最后将排序完毕的两组合并成一组,这组就是已经排序好的结果。

        在不断分组的过程中,最终会分到一个组只有一个元素的情况下,此时就不需要进行排序,直接进行合并即可。这也保证了方法递归终有结束的时候。

代码

void merge_sort(int a[],int start,int end){
    if(start < end){
        int min = (start+end)/2;
        merge_sort(a,start,min);
        merge_sort(a,min+1,end);
        merge(a,start,min,end);
    }
}

        上述代码会将序列进行分组排序,并调用merge进行合并。merge代码如下:

//合并两个分组
void merge(int a[],int start,int mid,int end){
    int b[end-start+1];//用于临时存储合并后的数据
    int i  = start,j = mid+1;
    int index = 0;
    while(i <= mid && j<=end){
        if(a[i] < a[j]){
            b[index] = a[i];
            i++;
        }else{
            b[index] = a[j];
            j++;
        }
        index++;
    }
    while(i<=mid){
        b[index++]=a[i++];
    }
    while(j<=end){
        b[index++]=a[j++];
    }
    i = start;
    for(index = 0;i<=end;index++,i++){
        a[i] = b[index];
    }
}

希尔排序

        参考

原理

        先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。

        下标为k的元素与k+gap,k+2*gap……等为一组,对每一组进行插入排序,并且随着gap的缩减不断进行排序。这样序列会越来越有序,相应地插入排序的效率会越来越高。

        其本质为:先分组,利用插入排序减少内部无序化,在整体进行一次插入排序。相当于先把一个大的数组分成几个小的数组插入排序,减少小数组中每个元素遍历次数提高在小数组中插入排序的效率。小数组有序后,再进行合并,这样就能提高大数组的有序性,进而提高对大数组执行插入排序的效率。

代码

void shellsort(int a[],int count){
    int gap = 0,j;
    for(gap = count /2;gap>0;gap /=2){
        for(j = gap;j<count;j++){
            if(a[j] < a[j-gap]){
                int value = a[j];
                int k = j-gap;//k表示当前元素value的前一个位置
                while(k>=0 && value<a[k]){
                    a[k+gap] = a[k];
                    k -= gap;
                }
                a[k+gap] = value;
            }
        }
    }
}
        上述代码的主要逻辑为:从gap处的元素进行同组插入排序,直到执行到序列的最后一个元素。




CCF大据与计算智能大赛-面向电信行业存量用户的智能套餐个性化匹配模型联通赛-复赛第二名-【多分类,embedding】.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值