数据结构和算法(排序)

排序:使一个无序序列转变为有序序列的过程

排序的稳定性:

假设ki = kj, (1<= i <= n, 1<= j <= n, i != j),且在排序前的序列中ri领先于rj(即i<j)

如果排序后ri仍领先于rj,则称所用的排序方法是稳定的,否则是不稳定的

影响排序算法性能的几个要素:

时间性能,辅助空间、算法的复杂性

 

冒泡排序:每次取相邻两个数做比较,并在符合交换条件时交换,直到整个数组均符合条件

#include <stdio.h>
#include <stdlib.h>

void Print(int *k, int n)
{
    int i;
    printf("此时的数组顺序为:\n");
    for(i=0; i<n-1; i++)
    {
        printf("%d ", k[i]);
    }
    printf("\n");
}

//不正宗的冒泡排序算法
void BubbleSort(int *k, int n)
{
    int i, j, temp, count1 = 0, count2 = 0;

    for(i=0; i<n-1; i++)
    {
        for(j=i+1; j<n; j++)
        {
            count1++;
            if(k[i] > k[j])
            {
                temp = k[j];
                k[j] = k[i];
                k[i] = temp;
                count2++;
            }
        }
    }
    Print(k, n);
    printf("此次共进行了%d次比较,%d次移动~\n", count1, count2);
}

//正宗的冒泡排序算法(从下往上冒)
void TrueBubbleSort(int *k, int n)
{
    int i, j, temp, count1 = 0, count2 = 0;

    for(i=0; i<n-1; i++)
    {
        for(j=n-1; j>i; j--)
        {
            count1++;
            if(k[j-1] > k[j])
            {
                temp = k[j];
                k[j] = k[j-1];
                k[j-1] = temp;
                count2++;
            }
        }
    }
    Print(k, n);
    printf("此次共进行了%d次比较,%d次移动~\n", count1, count2);
}

//正宗的冒泡排序算法优化
void BetterTrueBubbleSort(int *k, int n)
{
    int i, j, temp, count1 = 0, count2 = 0, flag = 1;

    for(i=0; i<n-1 && flag; i++)
    {
        flag = 0;
        for(j=n-1; j>i; j--)
        {
            count1++;
            if(k[j-1] > k[j])
            {
                temp = k[j];
                k[j] = k[j-1];
                k[j-1] = temp;
                count2++;
                flag = 1;
            }
        }
    }
    Print(k, n);
    printf("此次共进行了%d次比较,%d次移动~\n", count1, count2);
}

int main()
{
    int a[10] = {9,8,7,6,5,4,2,1,0,3};
    //int b[10] = {9,8,7,6,5,4,2,1,0,3};
    //int c[10] = {9,8,7,6,5,4,2,1,0,3};
    int n = 10;

    Print(a, n);
    printf("\n不正宗的冒泡排序:\n\n");
    BubbleSort(a, n);

    printf("\n正宗的冒泡排序:\n\n");
    TrueBubbleSort(a, n);

    printf("\n正宗的冒泡排序优化:\n\n");
    BetterTrueBubbleSort(a, n);

    return 0;
}

选择排序(一般比冒泡排序效率高):在数组中每次选取最大或最小的数移到最前面(迭代范围依次减1),直到数组有序

#include <stdio.h>

void Print(int *k, int n)
{
    int i;
    printf("此时的数组顺序为:\n");
    for(i=0; i<n-1; i++)
    {
        printf("%d ", k[i]);
    }
    printf("\n");
}

void SelectSort(int *k, int n)
{
    int i, j, min, temp;
    int count1 = 0, count2 = 0;

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

        for(j=i+1; j<n; j++)
        {
            if(k[j] < k[min])
            {
                min = j;
            }
        }

        if(min != i)
        {
            count2++;
            temp = k[min];
            k[min] = k[i];
            k[i] = temp;
        }
    }
    printf("此次共进行了%d次比较,%d次移动~\n", count1, count2);
}

int main(void)
{
    int a[10] = {9,8,7,6,5,4,2,1,0,3};
    int n = 10;

    Print(a, n);
    printf("\n选择排序:\n\n");
    SelectSort(a, n);
    return 0;
}

直接插入排序:每次将数组前面M个元素看作有序(M从1开始),将后面的元素与有序序列作比较并插入到相应的位置,重复前两步直至数组有序

#include <stdio.h>
#include <stdlib.h>

void Print(int *k, int n)
{
    int i;
    printf("此时的数组顺序为:\n");
    for(i=0; i<n; i++)
    {
        printf("%d ", k[i]);
    }
    printf("\n");
}

void InsertSort(int *k, int n)
{
    int i, j, temp;

    for(i=1; i<n; i++)
    {
        if( k[i] < k[i-1] )
        {
            temp = k[i];

            for(j=i-1; k[j]>temp; j--)
            {
                k[j+1] = k[j];
            }

            k[j+1] = temp;
        }
    }
    Print(k, n);
}

int main(void)
{
    //int a[10] = {5,2,6,0,3,9,1,7,4,8};
    int a[10] = {9,8,7,6,5,4,2,1,0,3};
    int n = 10;

    Print(a, n);
    printf("\n直接插入排序:\n\n");
    InsertSort(a, n);
    return 0;
}

希尔排序:时间复杂度(n*logn)每次排序取一定的间隔对子数组进行比较,期间间隔不断缩小直至为1

#include <stdio.h>
#include <stdlib.h>

void Print(int *k, int n)
{
    int i;
    printf("此时的数组顺序为:\n");
    for(i=0; i<n; i++)
    {
        printf("%d ", k[i]);
    }
    printf("\n");
}

void InsertSort(int *k, int n)
{
    int i, j, temp;
    int gap = n;

    do
    {
        gap = gap/3 + 1;

        for(i=gap; i<n; i+=gap)
        {
            if( k[i] < k[i-gap] )
            {
                temp = k[i];

                for(j=i-gap; k[j]>temp && j>=0; j-=gap)
                {
                    k[j+gap] = k[j];
                }

                k[j+gap] = temp;
            }
        }
    }while(gap > 1);
    Print(k, n);
}

int main(void)
{
    //int a[10] = {5,2,6,0,3,9,1,7,4,8};
    int a[10] = {9,8,7,6,5,4,2,1,0,3};
    int n = 10;

    Print(a, n);
    printf("\n希尔排序:\n\n");
    InsertSort(a, n);
    return 0;
}

堆排序:利用堆进行排序,将待排序的序列构造成堆(大顶堆或小顶堆),求最大值时取堆顶元素与末尾元素交换,再将剩余的元素重新构造成堆,重复上述操作,直至排序完成

#include <stdio.h>
#include <stdlib.h>

int count = 0;

void Print(int *k, int n)
{
    int i;

    printf("\n当前数组的顺序为:\n");
    for(i=1; i<=n; i++)
    {
        printf("%d ", k[i]);
    }
    printf("\n");
}

void swap(int *k, int i, int j)
{
    int temp;

    temp = k[i];
    k[i] = k[j];
    k[j] = temp;
}

void HeapAdjust(int *k, int s, int n)
{
    int i, temp;

    temp = k[s];

    for(i=2*s; i<=n; i*=2)
    {
        count++;
        if(i < n && k[i] < k[i+1])
        {
            i++;
        }

        if(temp >= k[i])
        {
            break;
        }

        k[s] = k[i];
        s = i;
    }

    k[s] = temp;
}

void HeapSort(int *k, int n)
{
    int i;

    for(i=n/2; i>0; i--)
    {
        HeapAdjust(k, i, n);
    }

    for(i=n; i>1; i--)
    {
        swap(k, 1, i);
        HeapAdjust(k, 1, i-1);
    }

    Print(k, n);
}

int main(void)
{
    int a[10] = {-1,8,7,6,5,4,2,1,0,3};
    int n = 9;

    Print(a, n);
    printf("\n堆排序:\n\n");
    HeapSort(a, n);

    printf("总共进行%d次比较~\n", count);
    return 0;
}

归并排序:

2路归并排序:将有n个记录的序列看成是拥有n个有序的子序列,每个子序列长度为1,然后两两归并,得到n/2个长度为2的有序子序列,在两两归并,依此类推,直到得到长度为n的有序序列

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10

//打印数组
void Print(int *k, int n)
{
    int i;

    printf("\n当前数组的顺序为:\n");
    for(i=0; i<n; i++)
    {
        printf("%d ", k[i]);
    }
    printf("\n");
}

//归并排序归并部分
void Merging(int *list1, int list1_size, int *list2, int list2_size)
{
    int i, j, k, m;
    int temp[MAXSIZE];
    i = j = k = 0;

    while(i<list1_size && j<list2_size)
    {
        if(list1[i] < list2[j])
        {
            temp[k++] = list1[i++];
        }
        else
        {
            temp[k++] = list2[j++];
        }
    }

    while(i < list1_size)
    {
        temp[k++] = list1[i++];
    }

    while(j < list2_size)
    {
        temp[k++] = list2[j++];
    }

    for(m=0; m<(list1_size + list2_size); m++)
    {
        list1[m] = temp[m];
    }
}

//归并排序递归部分
void MergeSort(int *k, int n)
{
    //将序列分为两部分,并且每部分与元素个数至少为2
    if(n > 1)
    {
        int *list1 = k;
        int list1_size = n/2;
        int *list2 = k + n/2;
        int list2_size = n - list1_size;

        MergeSort(list1, list1_size);
        MergeSort(list2, list2_size);

        Merging(list1, list1_size, list2, list2_size);
    }
}

int main(void)
{
    int a[10] = {9,8,7,6,5,4,2,1,0,3};
    int n = 10;

    Print(a, n);
    printf("\n堆排序:\n\n");
    MergeSort(a, n);
    Print(a, n);

    return 0;
}
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10

//打印数组
void Print(int *k, int n)
{
    int i;

    printf("\n当前数组的顺序为:\n");
    for(i=0; i<n; i++)
    {
        printf("%d ", k[i]);
    }
    printf("\n");
}

//归并排序迭代部分
void MergeSort(int *k, int n)
{
    int i, left_min, left_max, right_min, right_max, next;
    //分配一个动态内存用于存储排序后的序列
    int *temp = (int *)malloc(n * sizeof(int));

    if(!temp)
    {
        printf("分配动态内存失败!\n");
        exit(1);
    }

    //根据步长i对序列作比较
    for(i=1; i<n; i*=2)
    {
        //根据步长分配每个小区间的空间长度
        for( left_min = 0; left_min < n-i; left_min = right_max)
        {
            right_min = left_max = left_min + i;
            right_max = left_max + i;

            if(right_max > n)
            {
                right_max = n;
            }

            next = 0;

            while(left_min < left_max && right_min < right_max)
            {
                if(k[left_min] < k[right_min])
                {
                    temp[next++] = k[left_min++];
                }
                else
                {
                    temp[next++] = k[right_min++];
                }
            }

            //当左区间存在较大值时,将剩下的值放到右区间最右处
            while(left_min < left_max)
            {
                k[--right_min] = k[--left_max];
            }

            //将暂存在temp空间中的已排序序列放回原数组中
            while(next > 0)
            {
                k[--right_min] = temp[--next];
            }
        }
    }

}

int main(void)
{
    int a[10] = {9,8,7,6,5,4,2,1,0,3};
    int n = 10;

    Print(a, n);
    printf("\n堆排序:\n\n");
    MergeSort(a, n);
    Print(a, n);

    return 0;
}

快速排序:

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10

//打印数组
void Print(int *k, int n)
{
    int i;

    printf("\n当前数组的顺序为:\n");
    for(i=0; i<n; i++)
    {
        printf("%d ", k[i]);
    }
    printf("\n");
}

void swap(int *k, int low, int high)
{
    int temp;

    temp = k[low];
    k[low] = k[high];
    k[high] = temp;
}

int Partition(int *k, int low, int high)
{
    int point;

    point = k[low];

    while(low < high)
    {
        while(low < high && k[high] >= point)
        {
            high--;
        }
        swap(k, low, high);
        while(low < high && k[low] <= point)
        {
            low++;
        }
        swap(k, low, high);
    }

    return low;
}

void QSort(int *k, int low, int high)
{
    int point;

    if(low < high)
    {
        point = Partition(k, low, high);

        QSort(k, low, point-1);

        QSort(k, point+1, high);
    }
}

//快速排序
void QuickSort(int *k, int n)
{
    QSort(k, 0, n-1);
}

int main(void)
{
    int a[10] = {9,8,7,6,5,4,2,1,0,3};
    int n = 10;

    Print(a, n);
    printf("\n快速排序:\n\n");
    QuickSort(a, n);
    Print(a, n);

    return 0;
}


快速排序算法优化:

1.优化选取基准点:三数取中法,从序列中任意取三个数取中间的值作为基准点

2.优化掉不必要的交换:

3.优化小数组时的排序方案:待插入数组规模小,直接插入;大规模,快速排序(有递归)

4.优化递归操作:

优化示例:

/*快速排序算法的优化(三数取中法)*/
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10

//打印数组
void Print(int *k, int n)
{
    int i;

    printf("\n当前数组的顺序为:\n");
    for(i=0; i<n; i++)
    {
        printf("%d ", k[i]);
    }
    printf("\n");
}

void swap(int *k, int low, int high)
{
    int temp;

    temp = k[low];
    k[low] = k[high];
    k[high] = temp;
}

int Partition(int *k, int low, int high)
{
    int point;

    int m = low + (high - low)/2;

    if(k[low] > k[high])
    {
        swap(k, low, high);
    }
    if(k[m] > k[high])
    {
        swap(k, m, high);
    }
    if(k[m] > k[low])
    {
        swap(k, m, low);
    }

    point = k[low];

    while(low < high)
    {
        while(low < high && k[high] >= point)
        {
            high--;
        }
        swap(k, low, high);
        while(low < high && k[low] <= point)
        {
            low++;
        }
        swap(k, low, high);
    }

    return low;
}

void QSort(int *k, int low, int high)
{
    int point;

    if(low < high)
    {
        point = Partition(k, low, high);

        QSort(k, low, point-1);

        //QSort(k, point+1, high);
    }
}

//快速排序
void QuickSort(int *k, int n)
{
    QSort(k, 0, n-1);
}

int main(void)
{
    int a[10] = {9,8,7,6,5,4,2,1,0,3};
    int n = 10;

    Print(a, n);
    printf("\n快速排序:\n\n");
    QuickSort(a, n);
    Print(a, n);

    return 0;
}


排序算法:

1.插入排序类:直接插入排序,希尔排序

2.选择排序类:选择排序、堆排序

3.交换排序类:冒泡排序,快速排序

4.归并排序类:归并排序

各排序算法特点:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值