几个算法

来源:互联网 发布:tensorflow alphago 编辑:程序博客网 时间:2024/04/28 00:43
 

一、矩阵相乘动态规划

1.基本思想

在比较基本的算法设计思想里,动态规划是比较难于理解,难于抽象的一种,但是却又十分重要。动态规划的实质是分治思想和解决冗余,因此它与分治法和贪心法类似,它们都是将问题的实例分解为更小的、相似的子问题,但是动态规划又有自己的特点。

 

贪心法的当前选择可能要依赖于已经作出的选择,但不依赖于还未做出的选择和子问题,因此它的特征是由顶向下,一步一步地做出贪心选择,但不足的是,如果当前选择可能要依赖子问题的解时,则难以通过局部的贪心策略达到全局最优解。相比而言,动态规划则可以处理不具有贪心实质的问题。

 

在用分治法解决问题时,由于子问题的数目往往是问题规模的指数函数,因此对时间的消耗太大。动态规划的思想在于,如果各个子问题不是独立的,不同的子问题的个数只是多项式量级,如果我们能够保存已经解决的子问题的答案,而在需要的时候再找出已求得的答案,这样就可以避免大量的重复计算。由此而来的基本思路是,用一个表记录所有已解决的子问题的答案,不管该问题以后是否被用到,只要它被计算过,就将其结果填入表中。

 

比较感性的说,其实动态规划的思想是对贪心算法和分治法的一种折衷,它所解决的问题往往不具有可爱的贪心实质,但是各个子问题又不是完全零散的,这时候我们用一定的空间来换取时间,就可以提高解题的效率。

   2.程序

#include "iostream.h"

#include "stdio.h"

#define N 5

 

void Traceback(int i,int j,int s[][N])

{

  if(i==j)return;

  Traceback(i,s[i][j],s);

  Traceback(s[i][j]+1,j,s);

  cout<<"Multiply A"<<i<<","<<s[i][j];

  cout<<"and A"<<(s[i][j]+1)<<","<<j<<endl;

}

 

void MatrixChain(int *p,int n,int m[][N],int s[][N])

{ int i,r,j,k,t;

  for(i=1;i<=n;i++)m[i][i]=0;

  for(r=2;r<=n;r++)

    for(i=1;i<=n-r+1;i++)

    {j=i+r-1;

     m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];

     s[i][j]=i;

      for(k=i+1;k<j;k++)

      { t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];

        if(t<m[i][j])

        {m[i][j]=t;

         s[i][j]=k;

        }

      }

    }

}

 

 

 

void main()

{

  cout<<"动态规划求矩阵连乘计算次序最优解:/n";

  int s[N][N];

  int p[N];

  int m[N][N];

  int i;

  cout<<"初始化N=5个矩阵行列数:/n";

  for(i=0;i<N;i++)

  cin>>p[i];

  cout<<"输出结果:/n";

  MatrixChain(p,N,m,s);

  Traceback(1,N,s);

}

 

3.结果

 

.分治法同时求最大元最小元

1.分治法的基本思想

任何一个可以用计算机求解的问题所需的计算时间都与其规模N有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少。例如,对于n个元素的排序问题,当n=1时,不需任何计算;n=2时,只要作一次比较即可排好序;n=3时只要作3次比较即可,…。而当n较大时,问题就不那么容易处理了。要想直接解决一个规模较大的问题,有时是相当困难的。

分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。

如果原问题可分割成k个子问题(1<kn),且这些子问题都可解,并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。

2.程序

 

//******************************************

//用分治法同时求最大元和最小元

//******************************************

 

#include  "iostream.h"

#define  N 10

 

int max(int a,int b)

{

    return((a>b)?a:b);

}

 

int min(int a,int b)

{

    return((a<b)?a:b);

}

void Search(int a[],int *max0,int *min0,int n)

{int g[30];

 int i,m;

 int max1,max2,min1,min2;

  if(n==1)

  {*max0=a[0];

   *min0=a[0];

  }

  else if(n==2)

  {*max0=max(a[0],a[1]);

   *min0=min(a[0],a[1]);

  }

  else

  { m=n/2;

    for(i=0;i<m;i++)

     g[i]=a[i];

    Search(g,&max1,&min1,m);

    for(i=0;i<n-m;i++)

     g[i]=a[i+m];

    Search(g,&max2,&min2,n-m);

    *max0=max(max1,max2);

    *min0=min(min1,min2);

  }

  

}

void main()

{ cout<<"用分治法同时求最大元和最小元/n";

  int a[N];

  int i,max,min;

  cout<<"输入"<<N<<"个数:/n";

  for(i=0;i<N;i++)

  cin>>a[i];

  Search(a,&max,&min,N);

  cout<<"输出结果:/n";

  cout<<"max="<<max<<"/n";

  cout<<"min="<<min<<"/n";

}

3.结果

.分治法求最大元次大元

 1.分治法的基本思想(同上)

 2.程序

//******************************************

//用分治法同时求最大元和次大元

//******************************************

 

#include  "iostream.h"

#define  N 10

 

int max(int a,int b)

{

    return((a>b)?a:b);

}

 

int min(int a,int b)

{

    return((a<b)?a:b);

}

 

 

void Search(int a[],int *max0,int *second0,int n)

{int g[30];

 int i,m;

 int max1,max2,second1,second2;

  if(n==1)

  {*max0=a[0];

   *second0=a[0];

  }

  else if(n==2)

  {*max0=max(a[0],a[1]);

   *second0=min(a[0],a[1]);

  }

 

  else

  {  m=n/2;

    for(i=0;i<m;i++)

     g[i]=a[i];

     Search(g,&max1,&second1,m);

    for(i=0;i<n-m;i++)

     g[i]=a[i+m];

     Search(g,&max2,&second2,n-m);

     *max0=max(max1,max2);

     *second0=max(min(max1,max2),max(second1,second2));

     

  }

 

}

 

 

void main()

{ cout<<"用分治法同时求最大元和次大元/n";

  int a[N];

  int i,max,second;

  cout<<"输入"<<N<<"个数:/n";

  for(i=0;i<N;i++)

  cin>>a[i];

  Search(a,&max,&second,N);

  cout<<"输出结果:/n";

  cout<<"max="<<max<<"/n";

  cout<<"second="<<second<<"/n";

}

3.结果

 

 

 

 

 

 

 

 

: 冒泡排序  

1. 基本思想:

   比较相邻两个记录的关键字,若r[i].key>r[i+1].key,则交换之,其中i 0n-pass-1pass的初值为1)称之为一趟起泡排序, 其结果是使最大关键字的记录被交换到n-pass的位置上。

   如果某一趟起泡排序过程中没有进行一次记录的交换,则排序过程结束。最坏情况下需n-1趟排序。

   若记录序列的初始状态为"正序",则冒泡排序过程只需进行一趟排序,在排序过程中只需进行n-1次比较,且不移动记录;反之,若记录序列的初始状态为"逆序",则需进行n(n-1)/2次比较和记录移动。因此冒泡排序总的时间复杂度为O(n*n)

2.程序

//********************************************************

//冒泡排序

//********************************************************

#include  "stdio.h"

#include  "stdlib.h"

#define  N  10000

void main()

{

  int i,j,count=0;

  int a[N], t;

//随机产生N个数

  for(i=0;i<N;i++)

   a[i]= rand();

//排序

  for(i=0;i<N-1;i++)

    for(j=0;j<N-i-1;j++)

        if(a[j]>a[j+1])

        {

        t=a[j];

        a[j]=a[j+1];

        a[j+1]=t;

        }

//每行五列输出有序数

    for(i=0;i<N;i++)

    {

      if(count%5==0)printf("/n");

      count++;

      printf("%10d",a[i]);

    }

    printf("/n");

}

 

 

3.结果

.快速排序  

1.基本思想:

   首先选取一个记录作为枢轴(不失一般性,可选第一个记录),依它的关键字为基准重排其余记录,将所有关键字比它大的记录都排在它之后,而将所有关键字比它小的记录都排在它之前,由此完成一趟快速排序。之后,分别对由一趟排序分割而成的两个子序列进行快速排序。时间复杂度O(nlogn).

 2.程序

//**********************************************************

//快速排序

//**********************************************************

#include "stdio.h"

#include  "stdlib.h"

#define  N  10000

 

 

int Partition(int a[],int low,int high);

void  QuikSort(int a[],int low,int high);

 

void main()

{

  int i,count=0;

  int a[N];

//随机产生N个数

  for(i=0;i<N;i++)

   a[i]= rand();

//堆排序

  QuikSort(a,0,N-1);

//每行五列输出有序数

  for(i=0;i<N;i++)

  {

    if(count%5==0)printf("/n");

    count++;

    printf("%10d",a[i]);

  }

    printf("/n");

}

 

 

//递归调用实现快速排序

void  QuikSort(int a[],int low,int high)

{

    if(low<high)

    {

     int q=Partition(a,low,high);

     QuikSort(a,low,q-1);

     QuikSort(a,q+1,high);

    }

 

}

 

//交换顺序表alowhigh数值,实现枢轴前()不大()于它

int Partition(int a[],int low,int high)

{

 

 int q=a[low];

 while(low<high)

 {

    while(low<high&&a[high]>=q)

     --high;

 

     a[low]=a[high];

     while(low<high&&a[low]<=q)

     ++low;

    a[high]=a[low];

 

 }

    a[low]=q;

    return low;

}

 

 3.结果

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.堆排序

1.分析设计思想:
   首先将初始待排序记录序列建堆,则堆顶元素必为含最大关键字或最小关键字的记录,输出该记录,然后将剩余记录再调整为堆,如此反复,直至排序结束。
   在堆排序主要需解决两个问题:
   如何建堆? 在完全二叉树中,所有序号i>n/2的结点都是叶子,因此,以这些结点为根的子树均已是堆,这样只需将以序号为n/2, n/2-1, n/2-2,,1的结点为根、的子树都调整为堆即可。在按此次序调整每个结点时,其左、右子树均已是堆。
   ki的左、右子树已经是堆,如何将以ki为根的完全二叉树也调整为堆? 因ki的左、右子树已经是堆,所以必须在ki 和它的左、右孩子中选出最小(或最大)的结点放到ki的位置上,不妨设k2I关键字最小,将kik2I交换位置,而交换之后有可能导致以k2I为根的子树不再为堆,于是可重复上述过程,将以k2I为根的子树调整为堆,……,如此逐层下去,最多可能一直调整到树叶,此方法称为"筛选法"

2.程序

//*******************************************************

//堆排序

//*******************************************************

#include <dos.h>

#include <conio.h>

#include <math.h>

#include <stdio.h>

#include <stdlib.h>

#define MAXSIZE 100000 //排序表的最大容量

typedef struct //定义排序表的结构

{int elemword[MAXSIZE]; //数据元素关键字

int length; //表中当前元素的个数

}SqList;

void InitialSqList(SqList&); //初始化排序表

void HeapSort(SqList &); //堆排序

void HeapAdjust(SqList &,int,int); //堆调整

void PrintSqList(SqList); //显示表中的所有元素

 

void main()

{SqList L; //声明表L

char j='y';

//-------------------------程序说明-------------------------------

printf("本程序将演示堆排序的操作。/n");

//----------------------------------------------------------------

while(j!='n'&&j!='N')

{InitialSqList(L); //待排序列初始化

HeapSort(L); //堆排序

PrintSqList(L); //显示排序结果

printf("继续进行下一次排序吗?(Y/N)");

scanf(" %c",&j);

}

printf("程序运行结束!/n按任意键关闭窗口!/n");

getchar();getchar();

}

 

void InitialSqList(SqList &L)

{//表初始化

int i;

printf("请输入待排序的记录的个数:");

scanf("%d",&L.length);

for(i=1;i<=L.length;i++)

 L.elemword[i]= rand();

printf("输出待排序的记录的关键字(整型数):/n");

for(i=1;i<=L.length;i++)

{printf("%10d",L.elemword[i]);

 if(i%5==0)printf("/n");

}

}

 

void HeapSort(SqList &L)

{//对顺序表L做堆排序。

int i,t;

for(i=L.length/2;i>0;--i) //L.elemword[1..L.length]建成大顶堆

HeapAdjust(L,i,L.length);

for(i=L.length;i>1;--i)

{t=L.elemword[1]; //将堆顶记录和当前未经排序子序列L.elemword[1..i]

L.elemword[1]=L.elemword[i]; //中的最后一个记录相互交换

L.elemword[i]=t;

HeapAdjust(L,1,i-1); //L.r[1..i-1]重新调整为大顶堆

}

}

 

void HeapAdjust(SqList &H,int s,int m)

{//已知H.elemword[s..m]中除H.elemword[s]之外均满足堆的定义,本函数调整H.elemword[s]

//使H.elemword[s..m]成为一个大顶堆

int j,rc;

rc=H.elemword[s];

for(j=2*s;j<=m;j*=2) //沿关键字叫大的结点向下筛选

{if(j<m&&H.elemword[j]<H.elemword[j+1]) ++j; //j为关键字较大的记录的下标

if(rc>=H.elemword[j]) break; //rc应插入在位置s

H.elemword[s]=H.elemword[j];

s=j;

}

H.elemword[s]=rc; //插入

}

 

void PrintSqList(SqList L)

{//显示表中所有元素

int i;

printf("已排好序的序列如下:/n");

for(i=1;i<=L.length;i++)

{printf("%10d",L.elemword[i]);

 if(i%5==0)printf("/n");

}

 printf("/n");

}

 

3.结果

 

.基数排序 

1.基本思想

  实现排序主要是通过关键字间的比较和移动记录这两种操作,而实现基数排序不需要进行记录关键字间的比较,它是一种利用多关键字排序的思想,即借助"分配""收集"两种操作对单逻辑关键字进行排序的方法。

   基数排序的方法是:一个逻辑关键字可以看成由若干个关键字复合而成的,可把每个排序关键字看成是一个d元组:

   例如,如果关键字是数值,且其值在0~99范围内,则可把每一个十进制数字看成是一个关键字,即可认为K2个关键字(K0K1)组成,其中K0是十位数,K1是个位数。排序时先按 的值从小到大将记录分配到r个盒子中,然后依次收集这些记录,再按 的值分配到r个盒子中,如此反复,直到对分配后收集起来的序列,便是完全排序的状态,其中r称为基数。这个过程是按LSD(最低位优先法)进行排序的,即从最低数位关键字起,按关键字的不同值对序列中记录"分配""收集"的。基数的选择和关键字的分解法因关键字的类型而异。

   为了实现记录的"分配""收集",需设立r个队列,排序前将队列设置为空,分配时,将记录插入到各自的队列中去,收集时将这些队列中记录排在一起。

   一般采用静态链表作为记录序列的存储结构,并且不另外设置各链队列的结点空间,而是利用静态链表中的结点作为链队列中的结点,这样只需修改指针即可完?quot;分配""收集"任务。时间复杂度为Odn+rd))

 

  在基数排序算法中,没有进行关键字的比较和记录的移动,而只是顺链扫描链表和进行指针赋值,所以,排序的时间主要耗费在修改指针上。对于n个记录(假设每个记录含d个关键字,每个关键字的取值范围为rd个值)进行一趟分配的时间复杂度为On),进行一趟收集的时间复杂度为Ord),整个排序过程需要进行d趟分配和收集操作。因此,链式基数排序总的时间复杂度为Odn+rd))。

   n较小,d较大时,基数排序并不合适。只有当n较大,d较小时,特别是记录的信息量较大时,基数排序最为有效。基数排序中所需辅助空间为2rd个队列指针,另外每个记录中都增加了一个指针域。

2.程序

#include <iostream.h>

#include <iomanip.h>

 

// constant size must be defined as the array size for bucketSort to work

const int SIZE = 12;

 

void bucketSort( int [] );

void distributeElements( int [], int [][ SIZE ], int );

void collectElements( int [], int [][ SIZE ] );

int numberOfDigits( int [], int );

void zeroBucket( int [][ SIZE ] );

 

int main()

{

   int array[ SIZE ] = { 19, 13, 5, 27, 1, 26, 31, 16, 2, 9, 11, 21 };

 

   cout << "Array elements in original order:/n";

 

   for ( int i = 0; i < SIZE; ++i )

      cout << setw( 3 ) << array[ i ];

 

   cout << '/n';

   bucketSort( array );

 

   cout << "/nArray elements in sorted order:/n";

 

   for ( int j = 0; j < SIZE; ++j )

      cout << setw( 3 ) << array[ j ];

 

   cout << endl;

   return 0;

}

 

// Perform the bucket sort algorithm

void bucketSort( int a[] )

{

   int totalDigits, bucket[ 10 ][ SIZE ] = { 0 };

 

   totalDigits = numberOfDigits( a, SIZE );

 

   for ( int i = 1; i <= totalDigits; ++i ) {

      distributeElements( a, bucket, i );

      collectElements( a, bucket );

 

      if ( i != totalDigits )

         zeroBucket( bucket );  // set all bucket contents to zero

   }

}

 

// Determine the number of digits in the largest number

int numberOfDigits( int b[], int arraySize )

{

   int largest = b[ 0 ], digits = 0;

 

   for ( int i = 1; i < arraySize; ++i )

      if ( b[ i ] > largest )

         largest = b[ i ];

 

   while ( largest != 0 ) {

      ++digits;

      largest /= 10;

   }

 

   return digits;

}

 

// Distribute elements into buckets based on specified digit

void distributeElements( int a[], int buckets[][ SIZE ], int digit )

{

   int divisor = 10, bucketNumber, elementNumber;

 

   for ( int i = 1; i < digit; ++i )   // determine the divisor

      divisor *= 10;                 // used to get specific digit

 

   for ( int k = 0; k < SIZE; ++k ) {

      // bucketNumber example for hundreds digit:

      // (1234 % 1000 - 1234 % 100) / 100 --> 2

      bucketNumber = ( a[ k ] % divisor - a[ k ] %

                     ( divisor / 10 ) ) / ( divisor / 10 );

 

      // retrieve value in buckets[bucketNumber][0] to determine

      // which element of the row to store a[i] in.

      elementNumber = ++buckets[ bucketNumber ][ 0 ];

      buckets[ bucketNumber ][ elementNumber ] = a[ k ];

   }

}

 

// Return elements to original array

void collectElements( int a[], int buckets[][ SIZE ])

{

   int subscript = 0;

 

   for ( int i = 0; i < 10; ++i )

      for ( int j = 1; j <= buckets[ i ][ 0 ]; ++j )

         a[ subscript++ ] = buckets[ i ][ j ];

}

 

// Set all buckets to zero

void zeroBucket( int buckets[][ SIZE ] )

{

   for ( int i = 0; i < 10; ++i )

      for ( int j = 0; j < SIZE; ++j )

         buckets[ i ][ j ] = 0;

}

3.结果

 

.2-3树插入

1. 基本思想

2-3树即为三阶B-, B-树是一种平衡的多路查找树,一棵m阶的B-树,或为空树,或为满足下列特征的m叉树:

  ①树中每个结点至多有m棵子树;

  ②若根结点不是叶子结点,则至少有两棵子树;

  ③除根之外的所有非终端结点至少有棵子树;

   ④所有的非终端结点中包含下列信息数据:

  (nA0K1A1K2A2,…,KnAn

  其中,Kii=1,…,n)为关键字,Ki<Ki+1Ai为指向子树根结点的指针,且指针Ai1所指子树中所有结点的关键字均小于KiAn所指子树中所有结点的关键字均大于Knn为关键字的个数。

  ⑤所有的叶子结点都出现在同一层次上,并且不带信息。

  B+树是一种B-树的变形树,具体与B-树的差别见例题。

键树又称数字查找树,它是一棵度≥2的树,树中的每个结点中不是包含一个或几个关键字,而是只含有组成关键字的符号。

 2.程序

//****************************************

//2-3树插入程序                         

//****************************************

#include "iostream.h"

#define m 3   //定义B-树阶数,m=3即为2-3        

#define NULL 0

typedef struct BTNode   

{

    int keynum;

    struct BTNode *parent;

    int key[m+1];

    struct BTNode *ptr[m+1];

}BTNode,*BTree;

 

typedef struct

{

    BTNode *pt;

    int r;

    int tag;

}Result;

//查找

Result *Search(struct BTNode *T,int k)

{

    struct BTNode *p,*q;

    Result *s;

    s=NULL;

    p=T;

    q=NULL;

    int i=1,j;

    int found=0;

    while(p&&!found)

    {

        while(j<=p->keynum)     

        {if(k<p->key[i])i++;

          else

          {i=i-1;

            break;

          }

          j++;

        }

     if(i>0&&p->key[i]==k)found=1;

     else

     {q=p;

      p=p->ptr[i];

     }

    }

    if(found)

    {s->pt=p;

     s->r=i;

     s->tag=1;

     return s;

    }

     else

     { 

         s->pt=q;

         s->r=i;

         s->tag=0;

         return s;

     }

}

//插入

void Insert(struct BTNode *T,int k,struct BTNode *q,int i)

{

    struct BTNode *ap,*p,*c;

    ap=NULL;

    p=NULL;

    c=NULL;

    int x=k;

    int a,s;

    int finished=0;

    while(q&&!finished)

    {   q->key[i+2]=q->key[i+1];  //直接插入

        q->key[i+1]=x;

        q->ptr[i+2]=q->ptr[i+1];

        ap=q->ptr[i];

        q->keynum++;

        if(q->keynum<m)finished=1;//未溢出,插入成功

        else

        { if(m%2==0)

            s=m/2;

           else

               s=m/2+1;

         //分裂结点**************************

         p=q;

         ap->parent=p->parent;

         for(a=s;a<p->keynum;a++)

         ap->key[a+1-s]=p->key[a+1];

         for(a=s;a<=p->keynum;a++)

         ap->ptr[a-s]=p->ptr[a];

         //**********************************

         q=q->parent;

         if(q)i=Search(q,x)->r;

        }

    }

        if(!finished)

        {   c=new struct BTNode;

            c->keynum=1;

            c->parent=NULL;

            c->key[1]=x;

            c->ptr[1]=T;

        }

        cout<<"插入成功!"<<"/n";

}

void main()

{

    cout<<"2-3树插入程序"<<"/n";

    int k;

     struct BTNode *T;

     Result *q;

     T=new struct BTNode ;

     cout<<"输入待插关键字:"<<"/n";

         cin>>k;

         q=Search(T, k);

         Insert(T, k,q->pt,q->r);

}

.最优二叉搜索树

1.基本思想

2.程序

//********************************************************************

//最优二叉搜索树

//********************************************************************

#include "iostream.h"

#define N 5

 

void OptimaBinarySearchTree(int *a,int *b,int n,int m[][N],int s[][N],int w[][N])

{ int i,j,r,k,t;

  for(i=0;i<=n;i++)

  {

      w[i+1][i]=a[i];

      m[i+1][i]=0;

  }

  for(r=0;r<n;r++)

    for(i=1;i<=n-r;i++)

    {

        j=i+r;

        w[i][j]=w[i][j-1]+a[j]+b[j];

        m[i][j]=m[i+1][j];

        s[i][j]=i;

        for(k=i+1;k<=j;k++)

        {

            t=m[i][k-1]+m[k+1][j];

            if(t<m[i][j])

            { m[i][j]=t;

              s[i][j]=k;

              cout<<"最优解:s["<<i<<"]["<<j<<"]="<<s[i][j]<<"/n";

            }

        }

        m[i][j]+=w[i][j];

    }

}

 

void main()

{   cout<<"最优二叉搜索树"<<"/n";

    int i;

    int a[N],b[N];

    int m[N][N],s[N][N],w[N][N];

    cout<<"初始化概率数组a["<<N<<"]:/n";

    for(i=0;i<N;i++)

    cin>>a[i];

    cout<<"初始化概率数组b["<<N<<"]:/n";

    for(i=1;i<N;i++)

    cin>>a[i];

    OptimaBinarySearchTree(a,b,N,m,s,w);

}

3.结果

.模式匹配:

1.  基本思想:

这种算法是D.E.Knuth V.R.PrattJ.H.Morris同时发现的,因此人们称为KMP算法。此算法可以在O(n+m)的时间数量级上完成串的模式匹配操作。
     其基本思想是:每当匹配过程中出现字符串比较不等时,不需回溯i指针,而是利用已经得到的部分匹配结果将模式向右滑动尽可能远的一段距离后,继续进行比较。
     假设主串为s1s2,...sn",模式串为p1p2...pn",当主串中第i个字符与模式串中第j个字符失配(比较不等)时,主串第i字符(i指针不回溯)应与模式中哪个字符再比较?
     令当s[i]!=p[j]时,s[i]应与p[next[j]]进行比较。
       

     例如: P="abaabcac"

2程序:

//**************************************************************************

//模式匹配(KMP)程序                                                      

//**************************************************************************

 

#include "iostream.h"

#include "string.h"

#include "stdio.h"

 

void get_next(char *T,int *next)          //获取模式串右滑值next[i]

 {

    unsigned int i=1,j=0;

    next[1]=0;

    while(i<strlen(T)-1)

    {

        if(j==0||T[i]==T[j])

         {

            ++i;

            ++j;

            next[i]=j;

         }

         else j=next[j];

    }

 }

 

int Index_KMP(char *S,char *T,int pos,int *next)       

{

  int i=pos,j=1,lenS=strlen(S)-1,lenT=strlen(T)-1;     //1=<pos<=strlen(S)1;

  while(i<=lenS&&j<=lenT)

  { if(j==0||S[i]==T[j])

      {++i;

       ++j;

      }

    else j=next[j]; 

  }

  if(j>lenT) return (i-lenT);

  else return 0;

}

 

 void main()

 {

     

     char  S[256],  T[20];

      int next[20],pos,w;

      unsigned int i;

     cout<<"输入主串(不包括首字符)"<<endl;

     scanf("%s",S);

     cout<<"输入模式串(不包括首字符)"<<endl;

     scanf("%s",T);

     cout<<"输入主串匹配起始位置(1"<<strlen(S)-1<<")之间:";

     cin>>pos;

    get_next(T,next);  

    w=Index_KMP( S, T, pos, next);

    if(w==0)cout<<"匹配不成功!"<<'/n';

       else cout<<"匹配成功,从主串第"<<w<<"处找到匹配串"<<endl;

 }

 

3.结果:

 

原创粉丝点击