基本算法学习(一)—— 排序

排序

一、冒泡排序

  算法思想: 在每一次对比排序中将大的数放在后面,整个排下来后,就变成有序的数列了

  算法实现:
      1.(范围为整个数组),从前向后两两比较,如果前面比后面大就交换位置。第一遍后就将大的放在了最后
      2.(缩小范围),从头再次重复步骤一,直到数组有序为止

  图片说明:
  这里写图片描述

缩小范围继续比较

这里写图片描述

直到最后成为了一个有序的数组停止比较,算法复杂度为O( n2

  注意的地方:要注意的是for循环的循环次数,每次比较的次数为范围的长度减一

  代码实现:

#include "stdio.h"
#include "stdlib.h"

void bubbleSort(int *a, int len);
void swap(int *a, int *b);
void print_arr(int *a, int len);

int main()
{
    int  array[] = { 18, 12, 56, 34, 78, 90, 12 };
    bubbleSort(array, 7);
    print_arr(array,7);
    system("pause");
    return 0;
}
//冒泡排序
void bubbleSort(int *a, int len){
    for (int i = len; i > 0; i--){
        for (int j = 0; j < i-1; j++){
            swap(&a[j], &a[j + 1]);
        }
    }
}
//交换函数
void swap(int *a, int *b){
    int temp;
    if (*a > *b){
        temp = *a;
        *a = *b;
        *b = temp;
    }
}

结果:
这里写图片描述

二、直接选择排序

  算法思想:在限定的范围内选取最小值,然后缩小范围继续选择最小值

  算法实现:
      1.在1~n的范围内选择最小值,与第1个值交换位置
      2.缩小范围在2~n上选择最小值,与第2个值交换位置
      3. 按照规律重复上述步骤,最后得到一个有序数列

  图片说明:
这里写图片描述

  注意的地方:
      1. 为了实现交换这一步骤,我们在还需声名一个变量来存储我们找到的最小值在数组中的索引值
      2. 与冒泡排序不同的是,冒泡排序在范围内进行比较时,会进行多次交换。而直接选择排序是在一轮搜索后找到最小值才会进行交换。但时间复杂度仍然时 O(n2)

  代码实现:

#include "stdio.h"
#include "stdlib.h"
void SelectSort(int R[], int n);

int main()
{
    int  array[] = { 18, 12, 56, 34, 78, 90, 12 };
    SelectSort(array, 7);
    print_arr(array,7);
    system("pause");
    return 0;
}
void SelectSort(int R[], int n){
    int index = 0;
    int min = 0;
    for (int i = 0; i < n; i++){
        min = R[i];
        for (int j = i; j < n; j++){
            if (R[j] < min){
                min = R[j];
                index = j;
            }
        }
        swap(&R[i], &R[index]);
    }
}

void swap(int *a, int *b){
    int temp;
    if (*a > *b){
        temp = *a;
        *a = *b;
        *b = temp;
    }
}

三、直接插入排序

  算法思想: 待排序的数字插入到已经排好序的有序数列中

(摘自白话经典博客中的算法步骤,后有链接)
算法实现:
      1. 初始时,a[0]自成1个有序区,无序区为a[1..n-1]。令i=1
      2. 将a[i]并入当前的有序区a[0…i-1]中形成a[0…i]的有序区间。
      3. i++并重复第二步直到i==n-1。排序完成。

链接:这篇博文还详细讲解了直接插入排序的其他方法,可供参考
http://blog.csdn.net/morewindows/article/details/6665714

  图片描述:
这里写图片描述

  代码实现:

#include "stdio.h"
#include "stdlib.h"
void Insertsort1(int a[], int n);
void swap(int *a, int *b);

int main()
{
    int  array[] = { 18, 12, 56, 34, 78, 90, 12 };
    Insertsort1(array, 7);
    print_arr(array,7);
    system("pause");
    return 0;
}

void Insertsort1(int a[], int n)
{
    for (int i = 1; i < n; i++){
        for (int j = i - 1; j >= 0; j--){
            if (a[j] > a[j + 1]){
                swap(&a[j], &a[j + 1]);
            }
        }
    }
}

void swap(int *a, int *b){
    int temp;
    if (*a > *b){
        temp = *a;
        *a = *b;
        *b = temp;
    }
}

四、希尔排序

  算法思想: 是一种分组插入排序

(百度百科)
希尔排序是在直接插入排序上进行的改进,改进的原因:
1、插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
2、但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。

  算法实现:
      1.确定缩小增量n,抽取相隔n的数为一组,进行直接插入排序
      2. 减小缩小增量n的值,继续分组排序
      3. 直到增量的值变为1为止,停止排序

  图片说明:
这里写图片描述

  代码实现:

#include "stdio.h"
#include "stdlib.h"
void Insertsort1(int a[], int n);
void swap(int *a, int *b);
int main()
{
    int  array[] = { 18, 12, 56, 34, 78, 90, 12 };
    Insertsort1(array, 7);
    print_arr(array,7);
    system("pause");
    return 0;
}
void shellsort3(int a[], int n)
{
    int i, j, gap;

    for (gap = n / 2; gap > 0; gap /= 2)
    for (i = gap; i < n; i++)
    for (j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap)
        swap(&a[j], &a[j + gap]);
}

void swap(int *a, int *b){
    int temp;
    if (*a > *b){
        temp = *a;
        *a = *b;
        *b = temp;
    }
}

五、归并排序

  算法思想: 采用的分而治之的想法,先将大的分为小的子序列,然后再合并

  算法实现:
      1.把大序列分子序列,分成单位为1为止(递归)
      2. 创建一个辅助的空间,用来存放合并后的子序列
      3.合并子序列,合并的规则是,从两个子序列的头部开始比较,小的放到辅助空间中。
这样下来,算法的时间复杂度为 O(nlogn) ,空间复杂度为 O(n)

  注意的地方:
      1.分的时候用的是递归的方法
      2. 比较一定会有一个子序列有剩余的情况,这个时候要将剩余的部分添加到辅助空间上
      3. 最后不要忘了将辅助空间的序列重新添加到真正的合并后的序列上

  图片描述:
  (图片来自c语言中国网)
      这里写图片描述

  代码实现:

  c语言版

int main()
{
    int  array[] = { 18, 12, 56, 34, 78, 90, 12 };
    MergeSort(array, 0, 6);
    print_arr(array,7);
    system("pause");
    return 0;
}

    //归并排序
void Merge(int *a, int left, int mid, int right){
    int left_i = left;
    int right_i = mid+1;
    int p = 0;
    //声名辅助空间
    int *temp = (int *)malloc((right - left + 1)*sizeof(int));

    while (left_i <= mid && right_i <= right){
        temp[p++] = (a[left_i] <= a[right_i]) ? a[left_i++] : a[right_i++];
    }
    //将子序列1的剩余部分给辅助空间
    while (left_i <= mid)
    {
        temp[p++] = a[left_i++];
    } 
    //将子序列2的剩余部分给辅助空间
    while (right_i <= right)
    {
        temp[p++] = a[right_i++];
    }

    for (p = 0, left_i = left; left_i <= right; p++, left_i++)
    {
        a[left_i] = temp[p];                     //归并完成后将结果复制回R[low..high]  
    }

}

//分序列
void MergeSort(int *R, int low, int high)
{
    //用分治法对R[low..high]进行二路归并排序  
    int mid;
    if (low<high)
    {   
        mid = (low + high) / 2;               
        MergeSort(R, low, mid);          
        MergeSort(R, mid + 1, high);       
        Merge(R, low, mid, high);          
    }
}

六、快速排序

  算法思想: 快速排序是选择出一个标准A,然后将小于A的值放在A之前,大于A的值放在A之后.

  算法实现:
      1.选择数组中第一个元素作为标准A,从后面开始比较
      2.如果找到一个小于A的值B,就将B放在A的位置,然后从B之后开始找
      3.如果找到一个大于A的值C,就将C放在最开始B的位置上,
      4.依照上面的次序进行,直到从前面开始找的和从后面找的相遇,就将A放在相遇的位置.

  图片说明
这里写图片描述
  等到排序一遍后,大于标准值的值就被排在了标准值的后面,小于标准值的值就被排在了标准值的前面.然后再在两侧分别执行一遍排序.最后就可以将
无序的数组排列成从左到右的有序数组,时间复杂度是 O(nlogn) .

  注意的地方:
      1.我们首先要声明一个变量来存储我们的标准值.
      2.在发现比标准大或者比标准小的时候,不是与标准值进行交换,而是填补空缺的位置上的值(填坑)
      3.在填完坑后要即使移动指针,从坑后面的数开始找。
       4.这里面涉及递归的思想

  代码实现:

  C语言版



#include "stdio.h"
#include "stdlib.h"
void SwiftSort(int  *a, int left, int right);
void print_arr(int *a, int len);
int main()
{
    int  array[] = { 18, 12, 56, 34, 78, 90, 12 };//给了一个初始数组
    SwiftSort(array, 0, 6);
    print_arr(array,7);
    system("pause");//防止在vs中运行时看不到结果就闪退
    return 0;
}

void SwiftSort(int  *a, int left, int right){
    int i = left;
    int j = right;
    int save = a[left];

    //如果左边大于等于右边说明完成一组排序
    if (left < right){

        while (i < j){

            //去找比标准值小的数直到找到为止
            while (i < j && a[j] <= save){
                j--;
            }

            if (i < j)
                a[i++] = a[j];

            //去找比标准值大的数直到找到为止
            while (i < j && a[i] > save) // 从左向右找第一个大于等于x的数  
                i++;
            if (i < j)
                a[j--] = a[i];

        }

        a[i] = save; //不要忘了把标准值放进去
        SwiftSort(a, left, i - 1);
        SwiftSort(a, i + 1, right);
    }
}

void print_arr(int *a, int len){
    for (int i = 0; i < len; i++){
        printf("%i ", a[i]);
    }
}

结果:

这里写图片描述

总结

1、分而治之,讲整个大的排序变成每一小组的排序(希尔排序,归并排序)
2、用对比后交换代替找到后再调整位置

上述代码可以在我的下载资源中找到。

猜你喜欢

转载自blog.csdn.net/nanbei2463776506/article/details/60965325