排序算法:选择排序、插入排序、希尔排序

常规函数均采用如下形式(字符型排序):

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/*交换字符串两项*/
void exchange(char *in, int i1, int i2)
{
    char ch = (char)in[i1];
    in[i1] = in[i2];
    in[i2] = ch;
}
/*字符串长度*/
int length(char *in)
{
    int i=0;
    while(in[i] != '\0')
        i++;
    return i;
}
/*输出字符串*/
void showString(char *str)
{
    int N = length(str);
    int i=0;
    while(i<N)
    {
        printf("%c ",str[i]);
        i++;
    }
    printf("\n");
}

选择排序

找到数组中的最小元素,将它与数组的第一个元素交换位置。再从剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。不断进行这样的操作,直到将整个数组排序。

/*选择排序*/
void selectSort(char *in)
{
    int i, j, min;
    int N = length(in);
    for(i=0;i<N-1;i++)
    {
        min = i;
        for(j=i+1;j<N;j++)
        {
            if(in[j]<in[min]) min = j; 
        }
        exchange(in,i,min);
        showString(in);
    } 
}

   

选择排序需要 ~N^2/2 次比较和 ~N 次交换,它的运行时间与输入无关,这个特点使得它对一个已经排序的数组也需要这么多的比较和交换操作。

插入排序

插入排序从左到右进行,每次都将当前元素插入到左部已经排序的数组中,使得插入之后左部数组依然有序。

/*插入排序*/
void insertSort(char *in)
{
    int i, j;
    int N = length(in);
    for(i=1;i<N;i++)
    {
        for(j=i; j>0 && in[j]<in[j-1]; j--)
        {
            exchange(in,j,j-1);
            showString(in);
        }
    }
}

   

插入排序的复杂度取决于数组的初始顺序,如果数组已经部分有序了,那么插入排序会很快。
平均情况下插入排序需要 ~N^2/4 比较以及 ~N^2/4 次交换;
最坏的情况下需要 ~N^2/2 比较以及 ~N^2/2 次交换,最坏的情况是数组是逆序的;
最好的情况下需要 N-1 次比较和 0 次交换,最好的情况就是数组已经有序了。

插入排序对于部分有序数组和小规模数组特别高效。

希尔排序
对于大规模的数组,插入排序很慢,因为它只能交换相邻的元素,如果要把元素从一端移到另一端,就需要很多次操作。
希尔排序的出现就是为了改进插入排序的这种局限性,它通过交换不相邻的元素,使得元素更快的移到正确的位置上。

希尔排序使用插入排序对间隔 h 的序列进行排序,如果 h 很大,那么元素就能很快的移到很远的地方。通过不断减小 h,最后令 h=1,就可以使得整个数组是有序的。

/*希尔排序*/
void shellSort(char *in)
{
    int i, j;
    int N = length(in);
    int h = 1;
    while(h < N / 3) {
        h = 3 * h + 1; // 1, 4, 13, 40, ...
    }
    while (h >= 1) 
    {
        for (i = h; i < N; i++) 
        {
            for (j = i; j >= h && in[j]<in[j - h]; j -= h) 
            {
                exchange(in, j, j - h);
                printf("(%d,%d)%d, ",i,j,h);showString(in);
            }
        }
        h = h / 3;
    }
}

   

希尔排序的运行时间达不到平方级别,使用递增序列 1, 4, 13, 40, ... 的希尔排序所需要的比较次数不会超过 N 的若干倍乘于递增序列的长度。后面介绍的高级排序算法只会比希尔排序快两倍左右。

全部代码:

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

/*交换字符串两项*/
void exchange(char *in, int i1, int i2)
{
    char ch = (char)in[i1];
    in[i1] = in[i2];
    in[i2] = ch;
}
/*字符串长度*/
int length(char *in)
{
    int i=0;
    while(in[i] != '\0')
        i++;
    return i;
}
/*输出字符串*/
void showString(char *str)
{
    int N = length(str);
    int i=0;
    while(i<N)
    {
        printf("%c ",str[i]);
        i++;
    }
    printf("\n");
}
/*选择排序*/
void selectSort(char *in)
{
    int i, j, min;
    int N = length(in);
    for(i=0;i<N-1;i++)
    {
        min = i;
        for(j=i+1;j<N;j++)
        {
            if(in[j]<in[min]) min = j; 
        }
        exchange(in,i,min);
        showString(in);
    } 
}

/*插入排序*/
void insertSort(char *in)
{
    int i, j;
    int N = length(in);
    for(i=1;i<N;i++)
    {
        for(j=i; j>0 && in[j]<in[j-1]; j--)
        {
            exchange(in,j,j-1);
            showString(in);
        }
    }
}

/*希尔排序*/
void shellSort(char *in)
{
    int i, j;
    int N = length(in);
    int h = 1;
    while(h < N / 3) {
        h = 3 * h + 1; // 1, 4, 13, 40, ...
    }
    while (h >= 1) 
    {
        for (i = h; i < N; i++) 
        {
            for (j = i; j >= h && in[j]<in[j - h]; j -= h) 
            {
                exchange(in, j, j - h);
                showString(in);
            }
        }
        h = h / 3;
    }
}

/*main函数*/
int main(int argc, char**argv)
{
    char str[] = "hgfedbca";
    showString(str);
    shellSort(str);
    showString(str);
    
    return 1;
}
更多内容: https://github.com/CyC2018/Interview-Notebook

本文只是对Java代码进行了C语言重写,如有侵权请联系删除!

猜你喜欢

转载自blog.csdn.net/rong_toa/article/details/80241049
今日推荐