二分查找
首先二分查找是基于有序数组的查找,通过每次缩小区间来确定值的范围。但是也是很基础的算法不再赘述。
#include<stdio.h>
int BinaryChop(int arr[],int nLength,int nNum)
{
if(arr == NULL || nLength <= 0)return -1;
int nBegin;
int nEnd;
int nMid;
nBegin = 0;
nEnd = nLength-1;
while(nBegin <= nEnd)
{
nMid = nBegin + (nEnd-nBegin)/2;
if(arr[nMid] == nNum)
{
return nMid;
}
else if(arr[nMid] > nNum)
{
//左侧
nEnd = nMid-1;
}
else
{
//右侧
nBegin = nMid+1;
}
}
return -1;
}
int main()
{
int arr[] = {1,2,3,4,5,6};
int n = BinaryChop(arr,sizeof(arr)/sizeof(arr[0]),0);
printf("%d\n",n);
return 0;
}
哈西查找(harshsearch)
哈西查找的基础就是先创建一个哈希表,然后通过哈希表进行查询。
建表的过程就是通过对数据取模将数据放到相应下标对应的哈希表中然后。但如果有多个数据取模后有相同的下标,则需要一对应下标为头进行链表存储,这里建议用头插法,即可满足需求。
表建成之后就可以对数据进行分析。先取模然后到对应下标为头的链表中查询,如果数据查询成功,则返回true否则就是false。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct hash
{
int nValue;
struct hash *pNext;
}Hash;
Hash **CreateHashTable(int arr[],int nLength)
{
if(arr == NULL || nLength <= 0)return NULL;
Hash **pHash = NULL;
pHash = (Hash**)malloc(sizeof(Hash*)*nLength);
memset(pHash,0,sizeof(Hash*)*nLength);
//元素入表
Hash *pTemp = NULL;
int i;
int nIndex;
for(i = 0;i<nLength;i++)
{
nIndex = arr[i]%nLength;
pTemp = (Hash*)malloc(sizeof(Hash));
pTemp->nValue = arr[i];
pTemp->pNext = pHash[nIndex];
pHash[nIndex] = pTemp;
}
return pHash;
}
void HashSearch(Hash **pHash,int nLength,int nNum)
{
if(pHash == NULL || nLength <= 0)return;
int nIndex;
nIndex = nNum%nLength;
Hash *pTemp = pHash[nIndex];
//链表遍历
while(pTemp)
{
if(pTemp->nValue == nNum)
{
printf("%d\n",pTemp->nValue);
return;
}
pTemp = pTemp->pNext;
}
printf("failed.\n");
return;
}
int main()
{
int arr[] = {11,99,7,209,18,2,171,86,63,226,104};
int n = sizeof(arr)/sizeof(arr[0]);
Hash **pHash = CreateHashTable(arr,n);
HashSearch(pHash,n,20);
return 0;
}
KMP
哈哈哈 又是KMP,刚接触的时候就是一知半解,今天得完全搞定他。
KMP的核心思想就是求匹配串的next数组,而next数组就是每个位置前缀和后缀的匹配长度,
如: ababaca中next数组为0,0,1, 2,3, 0,1(一般next数组都是从-1算起但是我本人觉得从0算起更好理解(就可以直接定位到下一次i的位置),如果别扭的话将next数组逐个减一即可)
代码:
#include<stdio.h>stdio
#include<stdlib.h>
#include<string.h>
int* GetNext(char SubStr[],int Len)
{
if(SubStr==NULL||Len==0)
{
printf("GetNextError\n");
return NULL;
}
int i=0;
int j=1;
int *next=(int *)malloc(sizeof(int)*Len);
memset(next,0,sizeof(int)*Len);
next [0]=0;
while(j<Len)
{
if(SubStr[i]==SubStr[j])
{
next[j++]=++i;
}
else{
if(i==0)
{
next[j++]=0;
}
else{
i=next[i-1];
}
}
}
return next;
}
void KMP(char Str[],int Len1,char SubStr[],int SubLen)
{
int i=0;
int j=0;
int flag=0;
int *next=GetNext(SubStr,SubLen);
while(i<Len1)
{
if(Str[i]==SubStr[j])
{
i++;
j++;
if(j==SubLen)
{
flag=1;
break;
}
}
else{
//字串到头 主串挪动
if(j==0)
{
i++;
}
else{
j=next[j-1];
}
}
}
if(flag)
{
printf("index=%d",i-SubLen);
}
else{
printf("error\n");
}
for(int i=0;i<SubLen;i++)
{
free(next[i]);
}
next=NULL;
}
int main()
{
int len1,len2;
scanf("%d",&len1);
char str[len1];
scanf("%s",str);
scanf("%d",&len2);
char SubStr[len2];
scanf("%s",SubStr);
KMP(str,len1,SubStr,len2);
return 0;
}
sunday
suanday是简易版的查找字符串,功能和KMP相同但是算法不同
百度百科
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int *GetNext(char *match)
{
int *pNext = NULL;
pNext = (int*)malloc(sizeof(int)*256);
memset(pNext,-1,sizeof(int)*256);
int i;
for(i = 0;i<strlen(match);i++)
{
pNext[match[i]] = i;
}
return pNext;
}
int Sunday(char *src,char *match)
{
if(src == NULL || match == NULL)return -1;
//获得Next数组
int *pNext = NULL;
pNext = GetNext(match);
//匹配
int i = 0;
int j = 0;
int k = i;
while(i < strlen(src) && j < strlen(match))
{
if(src[i] == match[j])
{
i++;
j++;
}
else
{
//主串跳转 匹配串回到起始位置
if(k+strlen(match) < strlen(src))
{
k = k+strlen(match)-pNext[src[k+strlen(match)]];
i = k;
j = 0;
}
else
{
return -1;
}
}
}
//检测
if(j == strlen(match))
{
return k;
}
else
{
return -1;
}
}
int main()
{
int n;
n = Sunday("abcweaiewabdabc","abcabc");
printf("%d\n",n);
return 0;
}
值得注意的是将next数组初始化为-1可以简化步骤,因为当子串查找不到src[k+stren(match)]时就可以直接+1。