算法-线性表常见排序(插入,交换,选择)

线性表-排序

1.定义

基于线性表的排序
排序是计算机数据处理的基本操作和重要技术,能有效提高一个数据处理系统的运行效率.
排序设计要的几个要素
1.排序对象.待排序对象,通常是一个线性表
2.排序标准.定序的依据,由数据元素中一个或者一组数据项充当,这些数据项称为排序关键字,简称关键字
3.排序方向.按照关键字递增还是递减排序.
4.排序操作.排序方法和技术,即排序算法或可执行的排序程序.
5.排序结果.已排好序的序列,或称结果序列.

2.结构体

在SequenStruct.c

#include <stdio.h>

#define M 100
typedef struct {
    int data[M];
    int n;
}SEQUENLIST;

3.直接插入排序

3.1基本思想

直接插入排序的基本思想是:
1.把待排序序列一分为二,前部分为"已排序子序列",后部分为"待排序子序列".
2.排序过程即使把"待排序子序列"中的元素一个一个地插入到"已排序子序列"中正确位置上并保证有序
3.直到"待排序子序列"为空为止.

3.2算法思路

1.设顺序表S,存储一维数组,长度为n.i,j为整数变量.
2.i标记已排序子序列和待排序子序列的分界点,指向待排序子序列的第1个结点,也就是控制排序是否结束的标记.
3.j用于寻找插入位置时指示已排序子序列范围内的位置,初值为i-1,并且寻找过程中不断减1.
4.在第一个数组元素前增设一个数组元素S[0],称为"哨兵"结点,用于存储当前待插入的结点,以空出该结点原来的位置.
5.因为查找插入位置是从已排序子序列尾部向前进行,所以"哨兵"结点起监视查找终止作用.由于向已排序子序列插入结点时要后移一个结点位置
6.所以该方法是一边查找一边移动,这样不会造成结点丢失.

3.3算法实现

在Algorithm.h写出方法声明

/*
 直接排序算法
 */
SEQUENLIST istSortMethod(SEQUENLIST A);

在Algorithm.c中实现此方法

#include "Algorithm.h"

/*
 直接排序算法
 */
SEQUENLIST istSortMethod(SEQUENLIST S){
    //1.顺序表中第一个数据为"哨兵",不列入排序的对象
    int i,j;
    //2.如果顺序表中排序的数据就一个元素,算法结束
    if(S.n<=2){
        return S;
    }
    //3.将队列分为"已排序子序列"和"未排序子序列"
    //S.data[0]为哨兵,用于存在当前待插入的结点
    //已排序子序列:S.data[1],
    //待排序子序列:S.data[2]......S.data[S.n];
    for(i=2;i<S.n;i++){
        //3.1将要排序的数据赋给哨兵
        S.data[0]=S.data[i];
        //3.2哨兵在已排序子序列查找位置
        for(j=i-1;j>0;j--){
            //如果哨兵小于已排序子序列元素(从后往前查找),那么把当前位置往后移动一位
            if(S.data[0]<=S.data[j]){
                S.data[j+1]=S.data[j];
            }else{
                //如果哨兵和当前比较的大于等于,且终止循环
                break;
            }
            
        }
        //3.3把哨兵放在当前位置的后面,这句话要放在循环的后面,为了防止此时的哨兵是已排序子序列最小的,那么循环直接结束,直接放在了S.data[1]的位置,
        S.data[j+1]=S.data[0];
    }
    //4.将哨兵置为-1
    S.data[0]=-1;
    
    printf("直接排序成功succcess!\n");
    return S;
}


在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断

#include "Algorithm.h"
int main(int argc, const char * argv[]) {
   //直接排序算法
    printf("直接排序算法\n");
    //数据的第一个数据-1,作为哨兵
    SEQUENLIST A={{-1,4,6,1,5,9,7,4,6,8,3},11};
    
    printSequenList(A);
    A=istSortMethod(A);
    printSequenList(A);
}

3.4 打印结果

直接排序算法
sequen={{-1,4,6,1,5,9,7,4,6,8,3},11}
直接排序成功succcess!
sequen={{-1,1,3,4,4,5,6,6,7,8,9},11}
Program ended with exit code: 0

注意:
在创建顺序表的时候,把数据的第一个位置留了出来,作为哨兵,其实要排序的数据是从第二个位置到第n个位置

4.简单交换排序(冒泡排序)

4.1基本思想

简单交换排序又称冒泡排序.
比如:进行从小到大的排序.
基本思想:
1.就是把待排序序列分成"已排序子序列"和"未排序子序列"初始时,已排序序列为空.
2.先从待排序子序列(n)中,查找最小的结点然后放到已排序的序列中,
3.然后在从待排序的(n-1)个结点中再次查找出最小的结点,然后放到已排序子序列的后面,
4.这样一直循环,直到待排序序列为最后一个结点,已排序序列的长度为n-1.那么就直接把待排序的序列剩下的最后一个结点就是最大的,不需要比较,直接放到已排序子序列后面.
5.把关键字较小的节点看成"气泡",每次较小的气泡浮出了水泡,不断的向上"冒",所以简称"冒泡"排序.

4.2算法思路

设顺序表S,存储为一维数组,长度为n,要求用简单交换排序方法对其进行排序.排序的核心就是结点扫描.扫描就结点序列的循环过程.在扫描中,"最小"结点渐渐漂浮到它的正当位置.为此,用整数变量i来标记扫描完成后最小结点位置;同时也把扫描范围控制到i和n之间,i初始值为1,即表示第1趟扫描,也表示现在要漂浮出的最小结点必须存储在1号结点位置.i的终值是n-1.说明最多要作n-1次扫描,是一个循环.为控制扫描过程,还要设置一个变量j,j从n想i逐1推进,控制扫描过程的结束,对每一次扫描,j的初值总为n.

在排序过程中不断的进行排序,到最后也许一些顺序已经排序好,不会再发生结点的交换,就没有必要再次进行扫描查找,所以增加一个变量k=1;每次进行排序,也判断一下,如果k=1,在进行这一轮的扫描, 此时设置 k=0,在查找最小结点时候,如果发生了结点的交换k=1.如果在进行新一款的扫描查找的时候,如果发现k=0,那么就表示上一轮的扫描没有发生结点的交换,后面的顺序已经是正确的,那么没有比较进行此轮的循环遍历.

4.3算法实现

在Algorithm.h写出方法声明

/*
 冒泡排序
 */
SEQUENLIST sisSortMethod(SEQUENLIST A);

在Algorithm.c中实现此方法

#include "Algorithm.h"
SEQUENLIST sisSortMethod(SEQUENLIST S){
    //1.判断顺序表的结点数据的数量
    if(S.n<2){
        return S;
    }
    int count=0;
    
    int k=1;
    //2.查找扫描的次数,即:n-1次,并且k==1,表示前一次发生过结点交换
    for(int i=0;i<S.n-1 && k==1 ;i++){
        k=0;
        count++;
        //3.从待排序自序列,从后往前逐1扫描,直到i的位置
        for(int j=S.n-1;j>0;j--){
            count++;
            //3.1比较相邻结点的大小
            if(S.data[j]<S.data[j-1]){
                //3.2后面结点小于相邻的前一个结点数据,那么就交换
                int  temp=S.data[j-1];
                S.data[j-1]=S.data[j];
                S.data[j]=temp;
                //3.3 设置k=1,表示进行了结点的交换
                k=1;
            }
        }
    }
    
    printf("冒泡排序成功success! 排序次数:count=%d\n",count);
    return S;
}

在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断

#include "Algorithm.h"
int main(int argc, const char * argv[]) {
   //冒泡排序
     printf("冒泡排序\n");
    SEQUENLIST S={{88,9,10,7,55,54,98,97,100,99},10};
    printSequenList(S);
    
    S=sisSortMethod(S);
    printSequenList(S);
    
}

4.4 打印结果


冒泡排序
sequen={{88,9,10,7,55,54,98,97,100,99},10}
冒泡排序成功success! 排序次数:count=60
sequen={{7,9,10,54,55,88,97,98,99,100},10}

5.简单选择排序

5.1基本思想

1.简单选择排序的思想是基于简单交换排序.
2.简单排序有一个很大的缺点,每一次比较都有可能发生两点交换.而简单选择排序在一趟扫描结束后最多只有一次结点交换.显然时间效率比简单交换排序好多了.
3.设待定排序序列为{R1,R2,…Rn},要求对其进行递增方向的排序.
4.简单选择排序的基本思想是:
4.1.先对整个待排序序列进行扫描,先找到关键字最小的结点,并与第1个结点交换.称为第1趟扫描.
4.2.把待排序序列分成了"已排序子序列"和"待排序子序列"两部分.初始时,已排序子序列为空.
4.3.第二趟扫描对除了第一个结点以外的结点进行扫描,找到次小结点与第2个结点进行交换,已排序子序列增加了一个结点,待排序子序列减少一个结点.
4.4.如此反复,直到最后一个结点到位,所有结点都进入已排序子序列中,待排序子序列为空.
4.5.扫描开始时总是把待排序序列的第1个结点假设为最小结点,并记录它的位置号.在扫描过程中,若遇到比他更小的结点时就更换记录新位置号,使扫描完成后记录的位置号是最小结点的位置号.

5.2算法思路

1.设顺序表S,存储为一维数组,长度为n,
2.用简单选择排序方法对其进行排序.这个排序过程的n-1扫描是一个循环,控制每一个"最小"结点的选择.
3.每一次扫描也是一个循环,主要操作是比较.
4.设置整数i,j,k.
i控制扫描的循环,初值为1.
j控制扫描中的比较,初值值i+1.
k记录最小结点位置号,初值为i.

5.3算法实现

在Algorithm.h写出方法声明

/*
 简单选择排序
 */
SEQUENLIST sssSortMethod(SEQUENLIST S);

在Algorithm.c中实现此方法

#include "Algorithm.h"

SEQUENLIST sssSortMethod(SEQUENLIST S){
    
    //1.判断S数据长度
    if(S.n<2){
        return S;
    }
    int k;
    //2.开始最外层循环
    for(int i=0;i<S.n;i++){
        //3.使用k记录当前的位置号
        k=i;
        //4.开始查找数值最小的位置号
        for(int j=i+1;j<S.n;j++){
            //5.如果当前的位置的数据小于k所在的位置号
            if(S.data[j]<S.data[k]){
                //6.则把k作为新的位置号
                k=j;
            }
        }
        //7.判断k所在的位置号和i所在的位置号是否一样,如果不一样,表示找到了比S.data[i]位置更小的数据
        //交换两个节点数据
        if(k!=i){
            int  temp=S.data[i];
            S.data[i]=S.data[k];
            S.data[k]=temp;
        }
    }
    
    printf("简单选择排序成功sucess!\n");
    return S;
}

在main.c中的main方法(int main(int argc, const char * argv[]) {})调用此方法,并且进行判断

#include "Algorithm.h"
int main(int argc, const char * argv[]) {
   //简单选择排序
    printf("简单选择排序\n");
    SEQUENLIST B={{88,9,10,7,55,54,98,97,100,99},10};
    printSequenList(B);
    
    B=sssSortMethod(B);
    printSequenList(B);
    printf("\n");    
}

5.4 打印结果:

简单选择排序
sequen={{88,9,10,7,55,54,98,97,100,99},10}
简单选择排序成功sucess!
sequen={{7,9,10,54,55,88,97,98,99,100},10}

这里对简单基本排序算法的一些介绍和实现,直接插入排序,简单选择排序,简单交换排序.三个方法中简单交换排序效率比较高.

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值