数据结构之排序1(直接插入,冒泡,希尔,选择)

排序,应该可以说在数据结构中占很重要的位置,我们常用的排序算法,可以分为两组:
一种是比较排序,主要有:冒泡排序,选择排序,直接插入排序,归并排序,堆排序,快速排序,希尔排序。
另一种是非比较排序,主要有:计数排序,基数排序,桶排序等。
今天我写的是自己对于冒泡排序,选择排序,直接插入排序,希尔排序四个排序算法的浅见。
排序算法,因为是算法,很多同学会觉得很绕,理不清思路,其实没有很难理解,画图就是一个很容易帮我们理解的方法。

注:今天我举的所有例子都是从小到大排序哒、、、

一.冒泡排序(BubbleSort)
冒泡排序通俗的理解它的基本思想就是两个数比较,较大的往下沉,较小的往上冒。
也就是说比较相邻的两个数据,如果第二个数小,就交换位置。就这样两两比较,一直到比较最前两个数据。最终最小数被交换到起始的位置,这样第一个最小数的位置就排好了。继续重复上述过程,依次将第2.3…n-1个最小数排好位置。
这里写图片描述
平均时间复杂度是:O(n2)
这是外层一次for循环,内层循环一遍的结果,找到的是最小的一个元素,像这样重复外层for循环就能找到第二小,第三小,直到得到最后的结果!
接下来代码实现一下冒泡排序算法的函数;

void Bubble_Sort(int *arr,int len)//冒泡排序
{
    assert(arr != NULL);
    int i = 0;//控制外层循环
    int j = 0;//控制内层循环
    int tmp = 0;//交换时用到的临时量
    for(i = 0;i<len;i++)//外层for循环
    {
        for(j = 0;j < len - i - 1;j++)//内层for循环
        {
            if(arr[j]>arr[j+1])//从后往前判断两个数的大小,如果前一个数大就进入并交换
            {
                tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
            }
        }
    }
}

接下来我们来优化一下冒泡排序:

void Bubble_Sort(int *arr,int len)//冒泡排序
{
    assert(arr != NULL);
    int i = 0;//控制外层循环
    int j = 0;//控制内层循环
    int tmp = 0;//交换时用到的临时量
    bool swap;//这个变量是优化算法定义的一个布尔类型变量
    for(i = 0;i<len;i++)//外层for循环
    {
        for(j = 0;j < len - i - 1;j++)//内层for循环
        {
            swap = false;
            if(arr[j]>arr[j+1])
            {
                tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
                swap = true;
            }
        }
        if(!swap)
        {
            return;
        }
    }
}

大家可以看到,代码中我定义了一个布尔类型的swap变量,外层循环一进去将swap置为false,进入内层循环进行交换,在交换的最后将swap置为true,这里就是每次进入外层循环会判断一下swap的值,如果它为false,说明并没有进入内层交换,说明已经有序,直接退出,交换的少了,是冒泡的一种优化算法。

二. 选择排序(SelctionSort)
选择排序的基本思想:
在长度为n的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
第二次遍历n-2个数,找到最小的数值与第二个元素交换;
。。。
第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。

这里写图片描述

这里我画图模拟了外层一二次循环,你可以自己下去把图画完,我们来分析一下,i控制的是外层循环,这里定义一个index_min,我用m代替的,一开始把i赋值给index_min,之后用index_min和j进行比较,j的初始值是i+1,每次用index_min和j进行比较,如果index_min比j大,就把j赋值给index_min,出来判断一下,如果index_min不等于i,说明index_min和j交换律,就把index_min下标对应的值和j下标对应的值进行交换,j++,这样走到最后得到的是第一个数字最小的一个序列,这是到第二次外层循环,i++,再重复上面步骤,直到最后得到的就是从小到大的有序序列。
c语言代码实现如下:

void Select_Sort(int *arr,int len)//选择排序
{
    assert(arr != NULL);
    int tmp = 0;
    int i = 0;
    int minx_index = 0;
    for(i = 0;i < len-1;i++)
    {
        minx_index = i;
        for(int j = i+1;j < len;j++)
        {
            if(arr[j] < arr[minx_index])
            {
                tmp = arr[j];
                arr[j] = arr[minx_index];
                arr[minx_index] = tmp;
            }
        }
    }
}

三.直接插入排序(Insertion Sort)
直接插入排序,通俗来说就是两个比较,将第三个开始的值往前面的值里按大小插入。
具体算法描述如下:
1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已经排序的元素序列中从后向前扫描
3.如果该元素(已排序)大于新元素,将该元素移到下一位置
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5.将新元素插入到该位置后
重复步骤2~5

这里写图片描述

这个图似乎画的有点尴尬,大家凑活看,直接插入排序这里依然是双重for循环,i控制外层for循环,就是循环来比较,j控制里层for循环,控制的是比较完要插入时比要插入数大的数向后移的循环,其实也就是比它本身大的数的个数。

我用c语言代码实现一下:

void Insert_Sort2(int *arr,int len)//直接插入排序2
{
    assert(arr != NULL);
    int i = 0;//控制外层循环
    int tmp = 0;//交换时的一个中间量
    int j = 0;//控制内层循环
    for(i=1;i<len;i++)//外层循环
    {
        tmp = arr[i];
        for(j = i-1;j>=0;j--)
        {
            if(arr[j]>tmp)
            {
                arr[j+1] = arr[j];
            }
            else
            {
                break;//这里break之后出来执行的是arr[j+1] = tmp;
            }
        }
        arr[j+1] = tmp;
    }
}

大家可以看到我上面标注的是插入排序2,插入排序方法很多,我实现了两个,另外一种会贴在最后完整的源码中。

四.希尔排序(Shell)
希尔排序是插入排序的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
对于增量的要求是:一组互素的数,且最后一个必须为1

这里写图片描述

接下来我用c语言代码实现:

void Shell(int *arr,int len,int gap)//希尔排序
{
    assert(arr != NULL);
    int i = 0;//控制外层循环
    int j = 0;//控制内层循环
    int tmp = 0;//交换时的中间量
    for(i = gap;i<len;i++)//这里的gap是增量
    {
        tmp = arr[i];
        for(j = i-gap;j>=0;j-=gap)
        {
            if(arr[j]>tmp)
            {
                arr[j+gap] = arr[j];
            }
            else
            {
                break;
            }
        }
        arr[j+gap] = tmp;
    }
}
void Shell_Sort(int *arr,int len)
{
    assert(arr != NULL);
    int drr[] = {5,3,1};//定义一个数组存放增量
    int lend = sizeof(drr)/sizeof(drr[0]);//数组求长度
    for(int i=1;i<lend;i++)
    {
        Shell(arr,len,drr[i]);//调用Shell()函数
    }
}

那么,接下来我贴出全部源码,供你们参考:


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

void Insert_Sort1(int *arr, int len)  //直接插入排序1
{  
    assert(arr != NULL);
    int i = 0, j = 0;  
    for (i = 1; i < len; i++)  
        if (arr[i] < arr[i - 1])  
        {  
            int temp = arr[i];  
            for (j = i - 1; j >= 0 && arr[j] > temp; j--)  
                arr[j + 1] = arr[j];  
            arr[j + 1] = temp;  
        }  
}  

void Insert_Sort2(int *arr,int len)//直接插入排序2
{
    assert(arr != NULL);
    int i = 0;
    int tmp = 0;
    int j = 0;
    for(i=1;i<len;i++)
    {
        tmp = arr[i];
        for(j = i-1;j>=0;j--)
        {
            if(arr[j]>tmp)
            {
                arr[j+1] = arr[j];
            }
            else
            {
                break;
            }
        }
        arr[j+1] = tmp;
    }
}
void Shell(int *arr,int len,int gap)//希尔排序
{
    assert(arr != NULL);
    int i = 0;
    int j = 0;
    int tmp = 0;
    for(i = gap;i<len;i++)
    {
        tmp = arr[i];
        for(j = i-gap;j>=0;j-=gap)
        {
            if(arr[j]>tmp)
            {
                arr[j+gap] = arr[j];
            }
            else
            {
                break;
            }
        }
        arr[j+gap] = tmp;
    }
}
void Shell_Sort(int *arr,int len)
{
    int drr[] = {5,3,1};
    int lend = sizeof(drr)/sizeof(drr[0]);
    for(int i=1;i<lend;i++)
    {
        Shell(arr,len,drr[i]);
    }
}
void Select_Sort(int *arr,int len)//选择排序
{
    assert(arr != NULL);
    int tmp = 0;
    int i = 0;
    int minx_index = 0;
    for(i = 0;i < len-1;i++)
    {
        minx_index = i;
        for(int j = i+1;j < len;j++)
        {
            if(arr[j] < arr[minx_index])
            {
                tmp = arr[j];
                arr[j] = arr[minx_index];
                arr[minx_index] = tmp;
            }
        }
    }
}
void Bubble_Sort(int *arr,int len)//冒泡排序
{
    assert(arr != NULL);
    int i = 0;
    int j = 0;
    int tmp = 0;
    bool swap ;
    for(i = 0;i<len;i++)
    {
        for(j = 0;j<len-i - 1;j++)
        {
            swap = false;
            if(arr[j]>arr[j+1])
            {
                tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
                swap = true;
            }
        }
        if(!swap)
        {
            return;
        }
    }
}
void Show(int *arr,int len)
{
    for(int i = 0;i<len;i++)
    {
        printf("%d  ",arr[i]);
    }
    printf("\n");
}
int main()
{
    int ar[5] = {0,54,3,78,0};
    int len = sizeof(ar)/sizeof(ar[0]);
    Insert_Sort1(ar,len);
    Show(ar,len);

    Insert_Sort2(ar,len);
    Show(ar,len);

    Shell_Sort(ar,len);
    Show(ar,len);

    Bubble_Sort(ar,len);
    Show(ar,len);

    Select_Sort(ar,len);
    Show(ar,len);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39110766/article/details/79143104