zoukankan      html  css  js  c++  java
  • 排序算法

    1.冒泡排序

      比较相邻的元素,如果第一个比第二个大,则交换这两个的值,对每一对相邻的元素进行同样的操作,从第一对到最后一对,这样最大的元素就到最后面了。对于所有的元素再次进行同样的操作,不断重复,最后就会完成排序。

    原理图:

    void sort(int *a,int size)
    {
        int i,j,tmp;
        for(i=0;i<size-1;i++)
        {
            for(j=0;j<size-i-1;j++)
            {
                if(a[j] > a[j+1])
                {
                    tmp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = tmp;
                }
            }
        }
    }

    2.选择排序

      选定第一个元素作为标志位,后面的元素插进来时都要与它进行比较,如果是升序排序的话,比它大的就放后面,比它小的就放前面,将标志位改为比它小的元素,始终保证最前面的元素是最小的;降序排序就反过来,比它小的直接放后面,比它大的放前面,再将标志位改为比它大的元素。从第一个元素开始为标志位,下一轮的标志位是第二个元素(前面的已经排好序了),之后第三个,第四个....直到最后一个。这样就排好序了。

    //选择排序--升序
    void select_sort(int *arr,int size)
    {
      for(int i=0;i<size;i++)
      {
        for(int j=i+1;j<size;j++)
        {
          if(arr[i] > arr[j])
          {
            int t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
          }
        }
      }
    }

    3.插入排序

      插入排序比较直观一点,跟选择排序有点类似,第二个元素与第一个元素进行比较,大的放后面,小的放前面,这样前面两个就已经排好序了,第三个元素就从第一个元素开始比较,比第一个小就放在前面,比第二个大就放在后面,否则就放在中间,之后的每一个元素都是这样,分别与前面已经排好的每一个元素进行比较,最后放在比它小并且后面的值比它大的位置。(升序)

    void insert_sort(int *a,int size)
    {
        int i,j,tmp;
        for(i=1;i<size;i++)
        {
            if(a[i]<a[i-1])
            {
                tmp = a[i];
                for(j=i-1;j>=0 && a[j] > tmp;j--)
                {
                    a[j+1] = a[j];
                }
                a[j+1] = tmp;
            }
        }
    }

     4.快速排序

      基本思想:第一遍排序将数列分成两个部分,前半部分比中间的key值小,后半部分比中间的key值大,然后再在两部分之间再找个key值,再分别进行排序,不断的分成两部分,最后排序完成。

      步骤:从数列中挑出一个key值(随便选),分别从数列两端开始比较,i、j分别指向数列第一个和最后一个元素,第i个元素如果比key小,则i指向下一个元素,直到指向一个比key大的元素,然后把该元素跟key交换位置,交换之后,key还是原来的值,只是位置变了;接下来i不动,从最后一个元素开始,j指向的元素跟key比较,元素比key小,就交换位置,比key大则j指向前面一个元素,直到遇到比key小的元素;交换之后又从i开始....i跟j轮流开始,直到i=j,在把key的值填入这个位置,这样整个数列就以key分成两半了。接下来用同样的方法,在前半部和后半部分别找个key进行排序。

    int quick_sort(int *a,int low,int high)
    {
      if(low < high)
      {
        int i = low;
        int j = high;
        int k = a[low];
        
        while(i < j)
        {
          while(i < j && a[j] >= k)
          {
            j--;
          }
          if(i < j)
          {
            a[i++] = a[j];
          }
          while(i < j && a[i] < k)
          {
            i++;
          }
          if(i < j)
          {
            a[j--] = a[i];
          }
        }
        a[i] = k;
        //递归调用
        quick_sort(a,low,i-1);
        quick_sort(a,i+1,high);
      }
    }

     5.希尔排序

      基本思想:希尔排序实际上是插入排序的改进版,在插入排序的基础上增加了分组,会优先比较距离比较远的元素,又被称为缩小增量排序。

      步骤:按一定的间隔进行划分数列,然后在每一组中进行插入排序,第一次的间隔为size/n,即每隔(size/n)的距离取一个数字,将这些数字分为一组,就有很多组,分别进行快速排序,这些数组在原来的大的数列中的位置并没有变,只是每一小组中的位置换了而已,例如:第一组的位置是第1、4、7个位置,这个小组内部排好序之后的数字也是按顺序填入这三个位置中。第二次为size/2n...直到间隔为1,之后再排一次插入排序就可以了。

    void shell_sort(int a[],int n)
    {
      int i,j,k;
      int tmp,gap;
      for(gap = n/2;gap > 0;gap /=2)//选取步长
      {
        for(i = 0;i < gap;i++)//直接插入排序
        {
          for(j = i+gap;j < n;i+=gap)//每次都加上步长
          {
            if(arr[j] < arr[j-gap])
            {
              tmp = arr[j];
              k = j-gap;
              while(k >= 0 && arr[k] > tmp)//记录后移
              {
                arr[k+gap] = arr[k];
                k-=gap;
              }
            arr[k+gap] = tmp;//找到位置插入
          }
        }
      }
    }

    6.归并排序

      基本思想:归并排序是建立在归并操作上的排序算法,将数列分成很多的小的数列,将小数列内部排好序之后,再两两合并成多个数列,这些数列内部再进行排序,再两两合并...最后排好序了,其他排序都不需要额外申请空间,归并排序需要申请空间。

      步骤:将长度为n的数列分成两个长度为n/2的子数列,将这两个子数列再进行拆分,变成四个子数列,这四个子数列内部排好序后,前两个跟后两个子数列分别合并并且排序,得到两个排好序的子数列,再进行合并并且排序,就得到一个完整的排好序的数列了。

    //分组归并
    void merge(int arr[],int begin1,int end1,int begin2,int end2,int tmp[])
    {
      int k = begin1;
      int i = begin1,j = begin2;
      while(i <= end1 && j <= end2)
      {
        if(a[i] <= a[j])
          tmp[k++] = a[i++];
        else
          tmp[k++] = a[i++];
      }
      //将左边的元素放到tmp中
      while(i <= end1)
        tmp[k] = a[i++];
      while(j <= end2)
        tmp[k++] = a[j++];
      //将tmp中的数据拷贝到愿数组中相应的区间
      memcpy(a+begin1,tmp+begin1;sizeof(int)*(end2-begin1+1));
    }
    
    //归并排序
    void merge_sort(int *a,int ldft,int dight,int *tmp)
    {
      if(lefi > = right)return;
      //mid将数组一分为二
      int mid = left + ((right - left)>>1);
      //左边归并排序,不断递归
      mergsort(a,left,mid,tmp);
      //右边归并排序,不断递归
      mergsort(a,mid+1,right,tmp);
      //合并两个子数组
      merge(a,left,mid,mid+1,right,tmp);
    }

    7.二叉树排序

      基本思想,创建一个二叉树序树(把第一个数字放在根节点,取后面的数字与根节点比较,大的放右边,小的放左边),然后中序遍历得到有序数列。

    #include <stdio.h>
    #include <sys/time.h>
    #include <stdbool.h>
    #include <stdlib.h>
    
    int get_random_data(int type)
    {
        //1.获取系统时间
        struct timeval tv;
        gettimeofday(&tv, NULL);
        //设置随机数因子
        srandom(tv.tv_usec);
        return random()%type;
    }
    
    //设计一个树结构
    typedef struct BTree{
        int data;
        struct BTree *lchild;
        struct BTree *rchild;
    }Bitree;
    
    Bitree* create_tree_node(int data)
    {
        Bitree * root = (Bitree*)malloc(sizeof(Bitree));
        root->lchild = NULL;
        root->rchild = NULL;
        root->data = data;
        return root;
    }
    
    Bitree *create_sort_tree(Bitree* root,  int data)
    {
        if(root == NULL)
        {
            root = create_tree_node(data);
            return root;
        }
    
        //root不为空
        if(data > root->data)//把data插入到右边
        {
            root->rchild = create_sort_tree(root->rchild, data);
        
        }
        else//插入根的左边
        {
            root->lchild = create_sort_tree(root->lchild, data);
        }
        
        return root;
    }
    
    void mid_tree(Bitree* root)
    {
        if(root == NULL)return ;
    
        if(root->lchild !=  NULL)
        {
            mid_tree(root->lchild);
        }
        printf("%d ", root->data);
        if(root->rchild != NULL)
        {
            mid_tree(root->rchild);
        }
    }
    
    
    int main(void)
    {
        Bitree *root = NULL;
        for(int i=0; i<100; i++)
        {
            int data = get_random_data(100);
            printf("%d ", data);
            root = create_sort_tree(root, data);
        }
        printf("
    ");
    
    
        //通过中序号遍历
        mid_tree(root);
        printf("
    ");
        return 0;
    }

    还有什么堆排序、计数排序、桶排序,都太难了,我不会,就不写了。

    8.各种排序的复杂度如下图所示(下面这部分是引用自某不认识大佬的博客的图图片,地址贴在后面)

     稳定:如果a原本在b的前面,而a=b,排序之后a仍然在b的前面。

    不稳定:同上,但是排序后a在b的后面。

    时间复杂度:对排序算法的总操作次数,反应出当要排序的数列长度n变化时,操作次数呈现的规律。

    空间复杂度:指的是算法在计算机内执行的时候所需的存储空间的度量,也是数据规模为n的函数。

    PS:如果我哪里写错了,请指正,互相学习一下。

    复杂度的那部分内容转自:https://www.cnblogs.com/onepixel/articles/7674659.html

  • 相关阅读:
    mmap函数实现
    linux交换空间
    日志式文件系统
    Linux内核书籍
    进程状态
    form表单中enctype="multipart/form-data"的作用
    php导入excel表格
    什么是隐藏域
    把生成的excel文件直接提供为下载页效果
    到底什么是实例化
  • 原文地址:https://www.cnblogs.com/smallqizhang/p/12439313.html
Copyright © 2011-2022 走看看