串
1、串(string)是由零个或多个字符组成的有限序列,零个字符的串称为空串(null string),可直接用“”表示。
2、空格串:只包含空格的串,空格串有长度。
3、串中任意个数的连续字符组组成的子序列称为该串的子串,包含子串的串称为主串。
4、子串在主串中的位置就是子串的第一个字符在主串中的序号。
5、串的顺序存储结构是用一组地址连续的存储单元存储字符序列。
//朴素的模式匹配算法(串的定位操作通常称作串的模式匹配)
//对主串的每一个字符作为子串的开头,与要匹配的字符串进行匹配
//对主串做大循环,每个字符开头做T的长度小循环,直到匹配成功或完全遍历
//用基本数组实现
//返回子串在主串第pos个字符之后的位置,若不存在则返回0
int Index(String S,String T,int pos)
{
int i=pos;//i用于主串S中当前位置下标,若pos不为1则从pos位置开始匹配
int j=1;//j用于子串中当前位置下标值
while(i<S[0]&&j<T[0]) //字符串的长度存在S[0],T[0]中
{
if(S[i]==T[j])//两字母相等则继续
{
i++;
j++;
}
else//指针后退开始匹配
{
i=i-j+2;//关键代码,退回到上次匹配首位的下一位
j=1;//j退回到子串T的首位
}
}
if(j>T[0])
return i-T[0];
else
return 0;
}
//KMP模式匹配算法实现
//通过计算返回子串T的next数组
void get_next(String T,int *next)
{
int i,j;
i=1;
j=0;
nextval[1]=0;
while(i<T[0])//此处T[0]表示串T的长度
{
if(j==0||T[i]==T[j])//T[i]表示后缀的单个字符,T[j] 表示前缀的单个字符
{
++i;
++j;
if(T[i]!=T[j])//若当前字符与前缀字符不同
nextval[i]=j;//当前j为nextval在i位置饿值
else
nextval[i]=nextval[j];
}
else
j=next[j];//如果字符不同,则j值回溯
}
}
二叉树
二叉树(Binary Tree)是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根节点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
二叉树的遍历
二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问且仅被访问依次。
//二叉树的定义
//折半查找算法
//二叉树的二叉链表结点结构定义
typedef struct BiTNode//结点结构
{
TElemType data;//结点数据
struct BiTNode *lchild,*rchild;//左右孩子指针
}BiTNode,*BiTree;
//前序遍历算法 递归
void PreOrderTraverse(BiTree T)
{
if(T==NULL)
return ;
printf("%c",T->data);//显示结点数据,可以更改为其他对结点的擦操作
PreOrderTraverse(T->lchild);//先遍历左子树
PreOrderTraverse(T->rchild);//最后遍历右子树
}
//中序遍历算法 递归
void InOrderTraverse(BiTree T)
{
if(T==NULL)
return ;
InOrderTraverse(T->lchild);//中序遍历子树
printf("%c",T->data);//显示结点数据,可以更改为其他对结点操作
InOederTraverse(T->rchild);//最后中序遍历右子树
}
void InOrderTraverse(BiTree T)
{
if(T==NULL)
return ;
InOrderTraverse(T->lchild);
printf("%c",T->data);//显示结点数据
InOrderTraverse(T->rchild);
}
//后序遍历算法
void PostOrderTraverse(BiTree T)
{
if(T==NULL)
return ;
PostOrderTraverse(T->lchild);//先后序遍历左子树
PostOrderTraverse(T->rchild);//再遍历右子树
printf("%c",T->data);
}
//二叉树的建立,按前序输入二叉树中结点的值
//#表示空数,构造二叉树链表表示二叉树T
void CreatBiTree (BiTree T)
{
TElemType ch;
scanf("%c",ch);
if(ch=='#')
*T=NULL;
else
{
*T=(BiTree)malloc(sizeof(BiTNode));
if(!*T)
exit(OVERFLOW);
(*T)->data=ch;//生成根结点
CreateBiTree(&(*T)->lchild);//构造左子树
CreateBiTree(&(*T)->rchild);//构造右子树
}
}
图
图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个圆,V是图G中顶点的集合,E是图G中边的集合。
从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历(Traversing Graph。
深度优先遍历
深度优先遍历(Depth_First_Search)深度优先搜索,简称DFS
//邻接矩阵的深度优先递归算法
void DFS(MGraph G,int i)
{
int j;
visited[i]=TRUE;
printf("%c",G.vexs[i]);//打印顶点,也可以是其他操作
for(j=0;j<G.numVertexes;j++)
if(G.arc[i][j]==1&&!visited[j])
DFS(G,j);//对访问的邻接顶点递归调用
}
//邻接矩阵的深度遍历操作
void DFSTraverse(MGraph G)
{
int i;
for(i=0;i<G.numVertexes;i++)
visited[i]=FALSE;//初始所有顶点状态都是未访问过状态
for(i=0;i<G.numVertexes;i++)
if(!visited[i])//对未访问过的顶点调用DFS,若是连通图,只会执行一次
DFS(G,i);
}
//邻接表的深度优先递归算法
void DFS(GraphAdjList GL,int i)
{
EdgeNode *p;
visited[i]=TRUE;
printf("%c",GL->adjList[i].data);//打印顶点,也可是其他操作
p=GL->adjList[i].firstedge;
while(p)
{
if(!visited[p->adjvex])
DFS(GL,p->adjvex);//对未访问的邻结顶点递归调用
p=p->next;
}
}
//邻接表的深度遍历搜索
void DFSTraverse(GraphAdjList GL)
{
int i;
for(i=0;i<GL->numVertexes;i++)
visited[i]=FALSE;//将所有的顶点状态都是未访问过的状态
for(i=0;i<GL->numVertexes;i++)
if(!visited[i])//对未访问过的顶点调用DFS,若是连通图,只会执行一次
DFS(GL,i);
}
广度优先遍历
广度优先遍历(Breath_First_Search)广度优先搜索,简称BFS
//邻接矩阵的广度遍历算法
void BFSTraverse(MGraph G)
{
int i,j;
Queue Q;
for(i=0;i<G.numVertexes;i++)
visited[i]=FALSE;
InitQueue(&Q);//初始化一辅助用的队列
for(i=0;i<G.numVertexes;i++)//对每一个顶点做循环
{
if(!visited[i])//若是未访问过就处理
{
visited[i]=TRUE;//设置当前顶点访问过
printf("%c",G.vexs[i]);//打印顶点,也可以其他操作
EnQueue(&Q,i);//将此顶点入队列
while(!QueueEmpty(Q))//若当前队列不为空
{
DeQueue(&Q,&i);//将队中元素出队列,赋值给i
for(j=0;j<G.numVertexes;j++)
{
//判断其他顶点若与当前顶点存在边且未访问过
if(G.arc[i][j]==1&&!visited[j])
{
visited[j]=TRUE;//找到此顶点标记为已访问
printf("%c",G.vexs[j]);//打印顶点
EnQueue(&Q,j);//将找到的此顶点入队列
}
}
}
}
}
}
//邻接表的广度遍历算法
void BFSTraverse(GraphAdjList GL)
{
int i;
EdgeNode *p;
Queue Q;
for(i=0;i<GL->numVertexes;i++)
visited[i]=FALSE;
InitQueue(&Q)
for(i=0;i<GL->numVertexes;i++)
{
if(!visited[i])
{
visited[i]=TRUE;
printf("%c",GL->adjList[i].data);//打印顶点
EnQueue(&Q,i);
while(!QueueEmpty(Q))
{
DeQueue(&Q,i);
p=GL->adjList[i].firstedge;//找到当前顶点
while(p)
{
if(!visited[p->adjvex])//若此点未被访问
{
visited[p->adjvex]=TRUE;
printf("%c",GL->adjList[p->adjvax].data);
EnQueue(&Q,p->adjvex);//将此点入队列
}
p=p->next;//指针指向另一个邻接点
}
}
}
}
}
最小生成树
构造连通网的最小代价生成树称为最小生成树
普利姆(Prim)算法
//普利姆(Prim算法)
void MiniSPanTree_Prim(MGrph G)
{
int main,i,j,k;
int adjvex[MAXVEX];//保存相关顶点下标
int lowcoast[MAXVEX];//保存相关顶点间边的权值
lowcost[0]=0;//初始化第一个权值为0,即v0加入生成树
//lowcost的值为0,在这里就是此下标的顶点已经加入生成树
adjvex[0]=0;//初始化第一个顶点下标为0
for(i=1;i<G.numVertexes;i++)//循环除下标为0外的全部顶点
{
lowcost[i]=G.arc[0][i];//将v0顶点与之有边的权值存入数组
adjvex[i]=0;//初始化都为v0的下标
}
for(i=1;i<G.numVertexes;i++)
{
min=INFINITY;//初始化最小权值
//通常设置为不可能的大数字
j=1;k=0;
while(j<G.numVertexes)//循环全部点
{
if(lowcost[j]!=0&&lowcost[j]<min)
{//如果权值不为0且权值小于min
min=lowcost[j];//让当前权值成为最小值
k=j;//将当前最小值的下标存入k
}
j++;
}
printf("(%d,%d)",adjvex[k],k)//打印当前顶点边中权值最小边
lowcost[k]=0;//将当前顶点权值设置为0,表示此顶点已经完成为任务
for(j=1;j<G.numVertexes;j++)
{
if(lowcost[j]!=0&&G.arc[k][j]<lowcost[j])
{
//若下标为k的顶点各边权值小于此前这些未被加入生成树权值
lowcost[j]=G.arc[k][j];//将较小权值存入lowcost
adjvex[j]=k;//将下标为k的顶点存入adjvex
}
}
}
}
克鲁斯卡尔算法
//克鲁斯卡尔(Kruskal算法)
void MiniSpanTree_Kruskal(MGraph G)//生成最小生成树
{
int i,n,m;
Edge edges[MAXEDGE];//定义边集数组
int parent[MAXVEX]; //定义一维数组用来判断边与边是否形成环路
//省略将邻接矩阵G转化为边集数组edges并按权值由小到大排序代码
for(i=0;i<G.numVertexes;i++)
parent[i]=0;//初始化数组值为0
for(i=0;i<G.numEdges;i++)
{
n=Find(parent,edges[i].begin);
m=Find(parent,edges[i].end);
if(n!=m)//若n与m不相等,说明此边没有与现成生成树形成的 环路
{
parent[n]=m;//将此边的结尾顶点放入下边为起点的parent中
//表示此顶点已经在生成树集合中
printf("(%d,%d) %d",edges[i].begin,edges[i].end,edges[i].weight);
}
}
}
int Find(int *parent,int f)//查找连线顶点的尾部下标
{
while(parent[f]>0)
f=parent[f];
return f;
}