首页 > 编程语言 >希尔排序、快速排序、KMP算法

希尔排序、快速排序、KMP算法

时间:2023-03-18 14:55:35浏览次数:36  
标签:int pattern next gap 后缀 希尔 KMP 排序 data

希尔排序

  • 背景

    • 对N个样本进行排序,顺序为从小至大
  • 步骤

    • 第一步:对样本不断确定分组的间隔gap,确定分组次数X -》对应第一个循环
      • 第一次gap = N/2;第二次gap = gap/2;直至分成一组,即gap=1;
    • 第二步:从头开始遍历这X个组 -》对应第二个循环
      • 实际遍历的时候从gap开始依次遍历即可
    • 第三步:对第一步分组的内部M个元素进行排序
      • 从组内的第二个元素开始,与前面元素进行对比插入;直至从组内第M个开始;
  • 代码

    int shell_sort(vector<int> data){
        int gap = 0;//分组的跨度
        int i = 0, j = 0;
        for(gap = data.size()/2; gap >= 1; gap /= 2){// 分组的次数
            
            for(i = gap; i < data.size(); i++){// 每组遍历 
                
                int tmp = data[i];
                for(j = i-gap; j >= 0 && tmp < data[j]; j = j - gap){//组内排序
                	// 组内tmp和之前的组内元素进行对比,比该元素大的元素向后偏移1位;
                    //直到找到比tmp小的第一位元素x,将tmp赋值给x的下一位
                    data[j+gap] = data[j];
                }
                data[j+gap] = tmp;
            }
        }
        return 0;
    }
    

快速排序

  • 背景

    • 对N个样本进行排序,顺序为从小至大
  • 步骤

    • 第一步:选取哨兵(参考值),并保存哨兵 -》一般为当前集合的第一个元素
    • 第二步:为哨兵找到合适的位置 -》前面部分比哨兵大,后面部分比哨兵小
      • 从前到后,找第一个比哨兵大的数,赋值给哨兵的位置,此时值为x
      • 从后到前,找第一个比x小的数,赋值给哨兵的位置
      • 重复第一步第二步,直到i和j相遇,此时的位置刚好把哨兵的值夹在中间
    • 第三步:对分完之后子集合重复上述操作---》递归左右子集
  • 代码

    int sort(vector<int>& v, int left, int right){
        if(left >= right) return 0;
        
        int i = left;
        int j = right;
        int key = data[left];
    
        while (i < j){//保证i一定会与j相遇
    
            while(i < j && key < data[j]){//避免内部循环的时候i越过j
                j --;
            }
            
            data[i] = data[j];
            while(i < j && key >= data[i]){//避免内部循环的时候i越过j
                i ++;
            }
            data[j] = data[i];
        }//结束循环时i == j
        data[i] = key;//	找到了对应的中间位置,属于哨兵的位置
    
        sort(data, left, i-1);
        sort(right, i+1, right);
        
        return 0;
    }
    int quick_sort(vector<int>& data){
        sort(data, 0, data.size() - 1);
        return 0;
    }
    

KMP算法

  • 背景

    快速查找文本中相同字符串 -》利用匹配字符串pattern对文本字符串text进行搜索匹配

  • 前提说明

    ab      前缀:a                     后缀:b                   最长相等前后缀:0--》x
    abc     前缀:a,ab                  后缀:b,bc                最长相等前后缀:0--》x
    abca    前缀:a,ab,abc              后缀:a,bc,bca            最长相等前后缀:1--》a
    abcab   前缀:a.ab.abc.abca         后缀:b,ab,cab,bcab       最长相等前后缀:2--》ab
    abcabc  前缀:a,ab,abc,abca,abcab   后缀:c,bc,abc,cabc,bcabc  最长相等前后缀:3--》abc
    
    • 前缀和后缀
      • 前缀:不包含最后一个字符的前面的所有集合
      • 后缀:不包含第一个字符的后面的所有集合
    • 最长相等前后缀
      • 前缀和后缀中存在相等最大长度的字符串
    • next数组 -》也被称为前缀表
      • pattern中字符的滑动窗口从第一个字符不断后移,每一个窗口下的最长相等前后缀的集合
      • 例:上述next数组为next[6] = {0, 0, 0, 1, 2, 3}; -》字符有n个,数组大小为n
  • 步骤

    • 第一步:求出next数组
    • 第二步:利用next数组进行匹配字符串
  • 代码

    void make_next(const char * pattern, int * next){//	得到next数组-》前缀表
    
        int q = 0, k = 0;
        int m = strlen(pattern);
    
        next[0] = 0;//默认第一个字符的最长相等前后缀为0
        for(k = 0, q = 1; q < m; q ++){// 下文有k的含义,k遍历前面部分,q遍历后面部分
            // 不匹配进行回退,不止会回退一次
            while( k > 0 && pattern[q] != pattern[k]){
                k = next[k-1];
            }//最差情况k == 0
    
            if(pattern[q] == pattern[k]){
                k ++;
            }        
            next[q] = k;
        }
    }
    int kmp (const char * text, const char * pattern, int * next){
    
        int n = strlen(text);// 文本字符串长度
        int m = strlen(pattern);// 匹配字符串长度
    
        make_next(pattern, next);// 得到next数组
    
        int i, q;
    
        for(i = 0, q = 0; i < n; i ++){
            // 不匹配进行回退,不止会回退一次
            while( q > = && pattern[q] != pattern[i]){
                q = next[q-1];// 对next数组的指针进行回退
            }
    
            if(pattern[q] == text[i]){
                q ++;
            }
            
            if(q == m){
                return i-q+1;// 得到匹配字符串的初始位置
            }
            return -1;
        }
    }
    
  • 图示

    • 求出next数组img
    • 匹配字符串img
  • 额外说明

    • 求next数组的过程可以看作利用以求出的next数组,进行前面字符和后边字符的匹配

    • k = next[k-1] / q = next[q-1];

      • 这两个位置都是利用next数组进行回退
      • 因为一旦遇到不匹配的字符,对于pattern中该字符前面的字符串,后缀已经匹配相等的部分直接使用前缀相等的部分代替,从而减少匹配次数
    • 由于kmp中text字符串的指针一直处于线性遍历,因此时间复杂度相比于暴力遍历的时间复杂度有大部分降低

      • 暴力遍历的时间复杂度为O(m*n); -》m为text字符串长度,n为pattern字符串长度
      • kmp的时间复杂度为O(m); -》m为text字符串长度
    • k的含义:

      • 代表前面字符指向的位置
      • 已经前后缀匹配成功的个数

标签:int,pattern,next,gap,后缀,希尔,KMP,排序,data
From: https://www.cnblogs.com/zqurgy/p/17230610.html

相关文章

  • 排序组件的使用--OrderingFilter模块的使用
    1.排序组件(OrderingFilter)的用法:  2.响应结果的传参格式:ordering=字段名(不带‘-’是正序,带‘-’是倒序):  3.路由:  ......
  • 一个乱七八糟的冒泡排序
    Input:任意多组数据(保证最多只有5组)对于每组数据,有两行数第一行数n,代表接下来将有n个数第二行数有n个乱序数注意:冒泡排序的越界#include<iostream>usingnamespac......
  • 对n个整数冒泡排序
    对n个整数数进行冒泡排序步骤:首先需要一个整形数组来存放整数,然后输入n个数到数组中去然后对数组中的值两两比较,把最大(小)的放到最后去#include<stdio.h>#defineMAX......
  • c代码实现冒泡排序
    #define_CRT_SECURE_NO_WARNINGS#include<stdio.h>voidbubble_sort(intarr[],intsz){inti=0;for(i=0;i<sz-1;i++){intj=0;for(j=0;......
  • 漫画:什么是选择排序算法?
    选择排序是一种简单直观的算法,今天我们聊聊选择排序的思想,代码以及复杂度排序思想一天,小一尘和师傅下山去了,在集市中路经一个水果摊,只见水果摊上摆着色泽基本相同但大......
  • 漫画:什么是冒泡排序算法?
    面试官:写一个冒泡排序吧冒泡排序是一个比较经典和简单的排序算法,今天我们从从算法本身,时间复杂度以及稳定性方面来看看冒泡排序,这些方面也是研究其他排序算法的一般思......
  • 漫画:什么是插入排序算法?
    面试官:聊聊插入排序插入排序是一种比较简单直观的排序算法,适用处理数据量比较少或者部分有序的数据,今天我们来聊聊插入排序一、排序思想只见慧能拿出了一副牌,洗......
  • 漫画:什么是归并排序算法?
    归并排序是建立在归并操作的一种高效的排序方法,该方法采用了分治的思想,比较适用于处理较大规模的数据,但比较耗内存,今天我们聊聊归并排序一、排序思想一天,小一尘和慧能......
  • 漫画:什么是希尔排序算法?
    希尔排序(ShellSort)是以它的发明者DonaldShell名字命名的,希尔排序是插入排序的改进版,实现简单,对于中等规模数据的性能表现还不错一、排序思想前情回顾:漫画:什么是插入排......
  • 漫画:什么是堆排序算法?
    面试官:写一个堆排吧堆排是基于堆的一种排序算法,对于堆的了解,请看可以管理时间的二叉堆(如果对堆的插入和删除不清楚,强烈建议先看堆),今天我们聊聊堆排的思想,复杂度以及稳定......