day11(数据结构)排序方法

排序:

1. 影响排序的效率有哪些

  

    1)交换次数

   

    2)移动次数

2. 稳定排序和非稳定排序

    设文件f=R1……Ri……Rj……Rn)中记录RiRji≠jij=1……n)的key相等,即Ki=Kj

    若在排序前Ri领先于Rj,排序后Ri仍领先于Rj,则称这种排序是稳定的,其含义是它

    没有破坏原本已有序的次序。反之,若排序后RiRj的次序有可能颠倒,则这种排序

    是非稳定的,即它有可能破坏了原本已有序记录的次序。

   

    12 3 34a 1 423 34b

   

   

    //不稳定排序

   

    如果你排序结束后 34b   34a 的前面,说明相同数据被交换了为,此时称为不稳定排序

   

    1 3 12 34b 34a 423

   

    //稳定排序

    1 3 12 34a 34b 423

3. 排序方法  

///

3.1 冒泡排序

   

//1. 冒泡排序 O(n^2)

void bubbleSort(int *p, int n)

{

    int i,j;

    int temp;

    for(i = 0; i < n-1; i++)

    {

        for(j = 0; j < n-1-i; j++)

        {

            if(p[j] > p[j+1])

            {

                temp = p[j];

                p[j] = p[j+1];

                p[j+1] = temp;

            }

        }

    }

}

优化:设置标志记录每次排序是否交换,如果没有交换则代表已完成排序则不用继续比较了。

void bubbleSort(int *p, int n)

{

    int i, j;

    int temp;

    int flag = 0;

    for (i = 0; i < n - 1; i++)

    {

        flag = 0;

        for (j = 0; j < n - 1 - i; j++)

        {

            if (p[j] > p[j + 1])

            {

                temp = p[j];

                p[j] = p[j + 1];

                p[j + 1] = temp;

                flag=1;

            }          

        }

        if (0 == flag)

            break;

    }

}

///

    3.2 选择排序

   

    选择排序的原理与冒泡排序相比更加容易理解:选定一个标准位,将待排序序列中的元素与标准位元素逐一比较,反序则互换

    其中所谓的标准位实际上也是数组中的一个下标位,在选定了这个下标位之后,在一轮排序中这个标准位将不再移动,

    然后将待排序序列——也就是这个标准位之后所有元素组成的序列——中的元素逐个和标准位上的值进行比较

    如果某一个待排序序列上的值比标准位上的值更小(升序排序)或者更大(降序排序),那么就将这个元素和标准位上的元素进行互换即可

    标准位的选择一般选取待排序序列的第一个下标作为标准位使用

   

//选择排序O(n^2)

//不稳定举例

//33 68 46 33 25 80 19 12

void selectSort(int *p, int n)

{

    int i,j;

    int temp;

    for(i = 0; i < n-1; i++)

    {

        for(j = n-1; j > i; j--)

        {

            if(p[j] < p[i]) //p[i]代表每一轮的基准值 i是基准值的位置

            {

                temp = p[i];

                p[i] = p[j];

                p[j] = temp;

            }

        }

    }

}

///

   3.3 插值排序

//插值排序O(n^2)

    插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开 始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相 等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳 定的。     

    0 1 2  3   4 5  6

    6 2 3 'J' 5 9 'K' //最开始数组

思想:

//最开始

//裁判手里: 2 3 'J' 5 9 'K'

//我手里: 6

   

//3.插值排序(思想类似于斗地主抓牌)

    //每抓一张牌之后,都将自己手里的牌变成有序的

    //始终保证我手里的牌是有序的

 // 裁判员  5 9 'K'

 

 // 我:6 //默认最开始的时候,我的手里已经有了一张牌

 //抓一张牌

      2

      //2这张牌插入到我手里的牌中

      //将抓到的牌与当前我手里的牌进行追个比较如果找到的牌小,就交换位置

     

// 2 6

//再抓一张牌

      3

      //3这张牌插入到我手里的牌中

      //将抓到的牌与当前我手里的牌进行追个比较如果找到的牌小,就交换位置

// 2 3 6

 //再抓一张牌

      'J'

      //'J'这张牌插入到我手里的牌中

      //将抓到的牌与当前我手里的牌进行追个比较如果找到的牌小,就交换位置

// 2 3 6 //因为手里的牌永远是有序的,所以当抓到的'J'比手里面最大的6还大,那么也就没有必要再将'J'2 3比较

void insertSort(int *p, int n)

{

int i,j;

int temp;

for(i = 1; i < n; i++) //代表开始抓牌,因为默认手里已经有一张牌,所以i的下标 1开始,终止下标是数组中最后一个元素,也就是最后一张牌

{ //需要将每一张牌插入到手里

   

    for(j = i; j > 0; j--)//j == i 代表 j此时为你抓到的牌

    {

        if(p[j] < p[j-1]) //将抓到手里的牌与目前手里的牌进行比较,注意比较的顺序是从后往前比

        {

            temp = p[j];

            p[j] = p[j-1];

            p[j-1] = temp;

        }

        else

        {

            break;//因为手中的牌一直有序

        }

    }

}

///

3.4 拆半排序

//拆半排序 O(n^2)

在查找表中数据本身有序的前提下,可以使用折半查找来代替顺序查找,这种排序的算法就是折半插入排序算法。

思想:用拆半查找找到插入位置,然后进行插入。

#include <stdio.h>
void print(int a[], int n ,int i){
    printf("%d:",i);
    for(int j=0; j<8; j++){
        printf("%d",a[j]);
    }
    printf("\n");
}
void BInsertSort(int a[],int size){
    int i,j,low = 0,high = 0,mid;
    int temp = 0;
    for (i=1; i<size; i++) {
        low=0;
        high=i-1;
        temp=a[i];
        //采用折半查找法判断插入位置,最终变量 low 表示插入位置
        while (low<=high) {
            mid=(low+high)/2;
            if (a[mid]>temp) {
                high=mid-1;
            }else{
                low=mid+1;
            }
        }
        //有序表中插入位置后的元素统一后移
        for (j=i; j>low; j--) {
            a[j]=a[j-1];
        }
        a[low]=temp;//插入元素
        print(a, 8, i);
    }
  
}
int main(){
    int a[8] = {3,1,7,5,2,4,9,6};
    BInsertSort(a, 8);
    return 0;
}

///

3.5 快速排序

https://blog.csdn.net/justidle/article/details/104203963?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-104203963-blog-82587933.235^v38^pc_relevant_anti_t3_base&spm=1001.2101.3001.4242.1&utm_relevant_index=3icon-default.png?t=N7T8https://blog.csdn.net/justidle/article/details/104203963?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-104203963-blog-82587933.235%5ev38%5epc_relevant_anti_t3_base&spm=1001.2101.3001.4242.1&utm_relevant_index=3

//不稳定

#include <stdio.h>

//piovt 枢轴

int getPiovt(int *p,int low, int high)

{

    int flag = p[low];//flag是镖旗

    while(low < high)

    {

        //最开始从右向左进行扫描

        while(flag <= p[high] && low < high)//只要p[high] >= flag 那么就high--

            high--;

        if(low < high)

        {

            p[low] = p[high];//将小于flag的数移动到左边

            low++;//准备改变扫描的方向,从左向右进行扫描

        }

        while(flag >= p[low] && low < high)//只要p[low] <= flag 那么就low++

            low++;

        if(low < high)

        {

            p[high] = p[low];//将大于flag的数,移动到右边

            high--;//准备改变扫描的方向,从右往左进行扫描

        }

    }

    //flag赋值到枢轴位置

    p[low] = flag;

    return low;//最后循环结束low == high 此时的位置就是枢轴位置

}

void showArray(int *p, int n)

{

    int i;

    //从右向左进行扫描

    for(i = 0; i < n; i++)

    {

        printf("%d ",p[i]);

    }

    printf("\n");

}

//写一个递归函数,进行快排

void quickSort(int *p, int low,int high)

{

    int piovt = getPiovt(p,low,high);

    if(low < piovt-1)//递归快排枢轴的左侧

        quickSort(p,low,piovt-1);

    if(piovt+1 < high)//递归快排枢轴的右侧

        quickSort(p,piovt+1,high);

}

int main(int argc, const char *argv[])

{

    //快排思想:先找到枢轴的位置,枢轴左侧的数都小于等于枢轴位置数据,右侧大于等于

    int a[8] = {32,2,54,6,78,23,17,76};

    showArray(a,8);

    quickSort(a,0,7);

    printf("快速排序之后---------------\n");

    showArray(a,8);

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值