关于那些O(N^2)排序算法

关于时间复杂度为O(N^2)的算法

其实时间复杂度为O(N^2)的算法是很缓慢的,但简单。
在用于规模小或者非常小的数组时,它们的简单使它们胜过快速但复杂的的算法。
案例都以数组为操作对象,实际还可以用于其他对象,例如堆栈和队列等。

插入排序

插入排序实际上把一个数组划分两种数组来看,一个是已经排好序的一个是未排序的(等待排序的)。
这种方式类似于玩扑克牌时候排序,拿一张排一张。
算法的伪代码方便我们去理解算法。
以下给插入排序的伪代码

 /*
     * Insertionsort(Data: values[])
     * 		For i=0 To <len of values>-1
     * 			//将元素i移动到数组中已排序部分的合适位置上
     * 			<找到第一个位置j,满足j <i 且 values[j]> values[i]>
     * 			<将项移动到位置j>
     * 		Next i
     * End Insertionsort
     */

转换为C语言

void Insertionsort(int *values,int len)//插入排序
{
    for(int i=1;i<len;i++)//实际操作发现i不必等于0,因为在已排序的数组为空情况下,第一个元素只有一种排法
    {
        int j;
        int temp=values[i];
        for( j=i;j>0&&values[j-1]>temp;j--)
            values[j]=values[j-1];
        values[j]=temp;
    }
}

案例详解

例如要排序: 5 2 4 6 1 3
第一次循环 i=1,也就是需要排2的位置。
通过观察可知如果要非递减的方法去排序,2应该放在5的前面。
代码将2通过临时变量temp储存起来。然后进入循环:
循环开始j=i(=1),条件为j>0(防止越界)&&values[j-1]>temp(找位置)
然后循环体为挪位置。
? 5 4 6 1 3 //(?代表空着位置)
最后把2放进对应的位置
2 5 4 6 1 3 //(粗体代表已排序的数组)
第二次结果
2 4 5 6 1 3
第三次结果
2 4 5 6 1 3
因为5>6在内层循环一开始就不满足条件,循环退出,6还是在原位。
第四次(细讲找位置)
第四次就要排1的位置,首先j是从1的位置开始,判断6是否大于1.也就是说判断前一个是否大于后一个,如果大于那么就说明该待排序的元素位置在和其比较元素的前面,那么循环体就会把6放在1的位置将原来的1覆盖,也就是空出来原本6的位置,这样就可以将1重新放入数组并且不覆盖已有的排好序的元素,最后j–也就是再一次往前去判断。
过程细节:(划掉的元素为当前比较的对象,例如一开始和6去比较)
2 4 5 6 1 3
2 4 5 ? 6 3
2 4 ? 5 6 3
2 ? 4 5 6 3
? 2 4 5 6 3
最后因为前面没元素可比较(意味着到第一位了),条件一不满足,跳出循环将1放入数组内。
第五次结果
1 2 3 4 5 6

选择排序

选择排序的基本思想是找到输入序列种包含的最大元素(或最小元素)并且将它加入到一个不断增长的已排序序列末端(或开端)。
伪代码展示:

/*
     * Selectionsort(Data: values[])
     *      For i=0 To <len of values>-1
     *          //找到下标为i的元素
     *          <找到数组中满足j>=i的所有位置j中最小项>
     *          <交换values[i]和values[j]>
     *      Next i
     * End Selectionsort
     */

转换成C语言:

void Selectionsort(int *values,int n)//选择排序
{
    for(int i=0;i<n-1;i++)//最后自动归位所以可以变成n-1
    {
        int min=i;
        for(int j=i+1;j<n;j++)
            if(values[j]<values[min])
                min=j;
        if(min != i)//交换(判断需不需要)
        {
            int temp=values[min];
            values[min]=values[i];
            values[i]=temp;
        }
    }
}

案例细讲

例如: 7 5 6 1 3 2 8 0
首先记录最小元素的下标(某认为i即已经归为无需交换),然后在为排序的数组序列中找到最小的元素并且记录其下标。最后进行交换即可
第一次大循环结果:
0 5 6 1 3 2 8 7
第二次:
0 1 6 5 3 2 8 7
第三次
0 1 2 5 3 6 8 7
第四次
0 1 2 3 5 6 8 7
第五次
0 1 2 3 5 6 8 7
第六次
0 1 2 3 5 6 8 7
第七次
0 1 2 3 5 6 7 8
可见最后一个元素只有一种放法(即自动归位)

冒泡排序

冒泡排序利用:如果一个数组是无序的,它必然包含两个不符合排序规则的相邻元素。冒泡排序算法不断地检索数组,交换这样不合序的元素的位置,直到找不到需要交换的元素为止。
伪代码展示:

/*
     * Bubblesort (Data:values[])
     * //在数组完成排序前不断重复
     *      Boolean: not_sorted = True
     *      While(not_sorted)
     *          //假设我们没有找到需要交换的元素
     *          not_sorted = False
     *          
     *          //在数组中寻找不合序的相邻元素
     *          For i=0 To <len of values>-1
     *          //判断元素i与元素i-1是否合序
     *          If (values[i] < values[i-1]) Then
     *              //将他们交换
     *              Date : temp = values[i]
     *              values [i] = values[i-1]
     *              values[i-1] = temp
     *
     *              //数组还没有排好序
     *              not_sorted = True
     *          End If
     *      Next i
     * End While
     */

C语言代码实现:

#define True 1
#define Flase 0
void Bubblesort(int *values,int n)//冒泡排序1
{
_Bool not_sorted = True;
    while(not_sorted)
    {
        not_sorted = Flase;
        for(int i=0;i<n-1;i++)
        {
            if(values[i]>values[i+1])
            {
                int temp=values[i];
                values[i]=values[i+1];
                values[i+1]=temp;
                not_sorted= True;
            }
        }
    }
}

第二种版本(无判断有无排好序)

void Bubblesort(int *values,int n)//冒泡排序2
{
    for ( int i = 0; i < n - 1; i++){
        for (int j = 0; j < n - 1 - i; j++)
            {
            if (values[j] > values[j + 1])
            {
                int temp = values[j];
                values[j] = values[j + 1];
                values[j + 1] = temp;
            }
            }
}

以下为结合第一种和第二种的优点的优化冒泡

void Bubblesort(int *values,int n)//冒泡排序3
{
    _Bool not_sorted = True;int n_i=n-1;
    while(not_sorted)
    {
        not_sorted = Flase;
        for(int i=0;i<n_i;i++)
        {
            if(values[i]>values[i+1])
            {
                int temp=values[i];
                values[i]=values[i+1];
                values[i+1]=temp;
                not_sorted= True;
            }
        }--n_i;
    }
}

案例详解

例如 0 1 2 4 5 6 3 7 8 9
该数组大部分元素已经合序。在第一次检索数组时,算法发现6和3不合序,交换位置。
0 1 2 4 5 3 6 7 8 9
第二次发现5和3不合序,交换位置
0 1 2 4 3 5 6 7 8 9
第三次交换不合序的3和4。
0 1 2 3 4 5 6 7 8 9
最后一次没发现不合序的元素,结束算法。

冒泡排序算法优化

1.通过案例发现有些元素有可能可以一次性移动多个单位到对应位置,就无需每次都交换数值,将其重新放入数组种去。
2.一般化情况,算法可以在遇到上一次检索时最后交换的元素时结束此次检索。

最终优化代码:

以下为冒泡排序的双向版本,效率更高!

void Bubblesort_Final(int* values,int NumItems)//最终优化,冒泡排序
{
    int min = 0;
    int max = NumItems - 1;
    while (min < max)
    {
        int last_swap = min - 1;
        int i = min + 1;
        while (i <= max)
        {
            if (values[i - 1] > values[i])
            {
                int tmp = values[i - 1];
                int j = i;
                do
                {
                    values[j - 1] = values[j];
                    j++;
                    if (j > max) break;
                } while (values[j] < tmp);
                values[j - 1] = tmp;
                last_swap = j - 1;
                i = j + 1;
            }
            else
            {
                i++;
            }
        }
        max = last_swap - 1;
        last_swap = max + 1;
        i = max - 1;
        while (i >= min)
        {
            if (values[i + 1] < values[i])
            {
                int tmp = values[i + 1];
                int j = i;
                do
                {
                    values[j + 1] = values[j];
                    j--;
                    if (j < min) break;
                } while (values[j] > tmp);
                values[j + 1] = tmp;
                last_swap = j + 1;
                i = j - 1;
            }
            else
            {
                i--;
            }
        }
        min = last_swap + 1;
    }
}

具体说明可参考Wikipedia(维基百科):
https://en.wikipedia.org/wiki/Cocktail_shaker_sort

综合代码展示

#include <stdio.h>
#define Ntext 10
#define MIN 10
#define MAX 100000
#define True 1
#define Flase 0
void S_num(int *,int );
void P_num(int *,int );
void Insertionsort(int *,int);//插入排序
void Selectionsort(int *,int);//选择排序
void Bubblesort(int *,int);//冒泡排序
void Bubblesort_Final(int* values,int NumItems);//最终优化,冒泡排序
int count=0;//步骤数
//Sort (Date:values []);
    int main() {
    int a[MIN];int b[MAX];
    S_num(a,Ntext);
    //Insertionsort(a,Ntext);
    //Selectionsort(a,Ntext);
    //Bubblesort(a,Ntext);
    Bubblesort_Final(a,Ntext);
    P_num(a,Ntext);
    printf("%d",count);
    return 0;
}
void Insertionsort(int *values,int len)//插入排序
{
    /*
     * For i=0 To <len of values>-1
     * //将元素i移动到数组中已排序部分的合适位置上
     * <找到第一个位置j,满足j <i 且 values[j]> values[i]>
     * <将项移动到位置j>
     * Next i
     */
    int j;
    for(int i=1;i<len;i++)
    {
        int temp=values[i];
        for( j=i;j>0&&values[j-1]>temp;j--)
            values[j]=values[j-1];
        values[j]=temp;
        P_num(values,8);//观看过程
    }
    //7 5 6 1 3 2 8 0
    //1 5 6 7 3 2 8 0
    //1   5 6 7 2 8 0
    //  3
    //时间复杂度?
}
void Selectionsort(int *values,int n)//选择排序
{
    /*
     * For i=0 To <len of values>-1
     * //找到下标为i的元素
     * <找到数组中满足j>=i的所有位置j中最小项>
     * <交换values[i]和values[j]>
     * Next i
     */
    for(int i=0;i<n-1;i++)
    {
        int min=i;
        for(int j=i+1;j<n;j++)
            if(values[j]<values[min])
                min=j;
        if(min != i)
        {
            int temp=values[min];
            values[min]=values[i];
            values[i]=temp;
        }
        P_num(values,8);//过程演示
    }
    //7 5 6 1 3 2 8 0
    //0 1 2 8 7 3 6 5
    //0 1 2 3 7 8 6 5
}
void Bubblesort(int *values,int n)//冒泡排序
{
        //int count=0;//计数,查看循环次数
#if 0 //原始
    for ( int i = 0; i < n - 1; i++){
        for (int j = 0; j < n - 1 - i; j++)
            {
            if (values[j] > values[j + 1])
            {
                int temp = values[j];
                values[j] = values[j + 1];
                values[j + 1] = temp;
            }
                count ++;
            }
}
//0 1 2 4 5 6 3 7 8 9
//0 1 2 4 5 3 6 7 8 9
//0 1 2 4 3 5 6 7 8 9
//0 1 2 3 4 5 6 7 8 9
#endif
    /*
     * Boolean: not_sorted = True
     * While(not_sorted)
     * //假设我们没有找到需要交换的元素
     * not_sorted = False
     * //在数组中寻找不合序的相邻元素
     * For i=0 To <len of values>-1
     * If (values[i] < values[i-1]) Then
     * //将他们交换
     * Date : temp = values[i]
     * values [i] = values[i-1]
     * values[i-1] = temp
     *
     * //数组还没有排好序
     * not_sorted = True
     * End If
     * Next i
     * End While
     */
#if 0// 优化 1
    _Bool not_sorted = True;
    while(not_sorted)
    {
        not_sorted = Flase;
        for(int i=0;i<n-1;i++)
        {
            if(values[i]>values[i+1])
            {
                int temp=values[i];
                values[i]=values[i+1];
                values[i+1]=temp;
                not_sorted= True;
            }
            count++;
            P_num(values,Ntext);
        }
    }
    //0 1 2 4 5 6 3 7 8 9
    //0 1 2 7 4 5 6 3 8 9
#endif
#if 0 //原始优化 1.1
    for ( int i = 0; i < n - 1; i++){
        _Bool not_sorted=True;
        for (int j = 0; j < n - 1 - i; j++)
            {
            if (values[j] > values[j + 1])
            {
                int temp = values[j];
                values[j] = values[j + 1];
                values[j + 1] = temp;
                not_sorted=Flase;
            }
                count ++;
            }
        //not_sorted? (break) :NULL;
        if(not_sorted)break;
}
//0 1 2 4 5 6 3 7 8 9
//0 1 2 4 5 3 6 7 8 9
//0 1 2 4 3 5 6 7 8 9
//0 1 2 3 4 5 6 7 8 9
#endif
#if 0 //优化3(false)
    _Bool not_sorted = True;
    while(not_sorted)
    {
        not_sorted = Flase;
        for(int i=1;i<n-1;i++)
        {
            if(values[i]<values[i-1])
            {
                int temp=values[i-1];
                _Bool sorted_=1;
                for(int j=i;j<n-1;j++)
                {
                    if(values[j]>temp)
                    {
                        values[i-1]=values[j-1];
                        values[j-1]=temp;
                        sorted_=0;
                    }
                    count++;
                }
                if(sorted_)
                {
                    values[i]=values[i-1];
                    values[i-1]=temp;
                }
                not_sorted= True;
            }
            P_num(values,Ntext);
        }
    }
    //0 1 2 4 5 6 3 7 8 9
    //0 1 2 5 4 6 3 7 8 9
#endif
#if 0 //优化2
    _Bool not_sorted = True;int n_i=n-1;
    while(not_sorted)
    {
        _Bool last_sorted = Flase;
        not_sorted = Flase;
        for(int i=0;i<n_i;i++)
        {
            if(values[i]>values[i+1])
            {
                int temp=values[i];
                values[i]=values[i+1];
                values[i+1]=temp;
                not_sorted= True;
                //log i+1; Then False all i=i+1;
                n_i=i+1;
            }
            count++;
            //P_num(values,Ntext);
        }
    }
    //0 1 2 4 5 6 3 7 8 9
    //4 1 5 6 1 6 3 8 9 10
    //6 1 8 2 9 4 3 7 5 0  False
#endif
#if 1 //优化2.1
    _Bool not_sorted = True;int n_i=n-1;
    while(not_sorted)
    {
        not_sorted = Flase;
        for(int i=0;i<n_i;i++)
        {
            if(values[i]>values[i+1])
            {
                int temp=values[i];
                values[i]=values[i+1];
                values[i+1]=temp;
                not_sorted= True;
            }
            count++;
            //P_num(values,Ntext);
        }--n_i;
    }
    //0 1 2 4 5 6 3 7 8 9
    //4 1 5 6 1 6 3 8 9 10
    //6 1 8 2 9 4 3 7 5 0
#endif
    //printf("%d\n",count);
}
void Bubblesort_Final(int* values,int NumItems)//最终优化,冒泡排序
{
    int min = 0;
    int max = NumItems - 1;
    while (min < max)
    {
        int last_swap = min - 1;
        int i = min + 1;
        while (i <= max)
        {
            if (values[i - 1] > values[i])
            {
                int tmp = values[i - 1];
                int j = i;
                do
                {
                    values[j - 1] = values[j];
                    j++;count++;
                    if (j > max) break;
                } while (values[j] < tmp);
                values[j - 1] = tmp;
                last_swap = j - 1;
                i = j + 1;
            }
            else
            {
                i++;count++;
            }
        }
        max = last_swap - 1;
        last_swap = max + 1;
        i = max - 1;
        while (i >= min)
        {
            if (values[i + 1] < values[i])
            {
                int tmp = values[i + 1];
                int j = i;
                do
                {
                    values[j + 1] = values[j];
                    j--;count++;
                    if (j < min) break;
                } while (values[j] > tmp);
                values[j + 1] = tmp;
                last_swap = j + 1;
                i = j - 1;
            }
            else
            {
                i--;count++;
            }
        }
        min = last_swap + 1;
    }
}
void S_num(int *values,int n)
{
    for(int i=0;i<n;i++)
        scanf("%d",values+i);
}
void P_num(int *values,int n)
{
    for(int i=0;i<n;i++)
        printf("%d",*(values+i));
    printf("\n");
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值