基本操作
InitList(&L)
InitList(&L)
{
}
//操作结果:构造一个空的线性表L
CreatList(&L,n)
void CreateList(LinkList &L, int n)
{
L = new LNode; L->next = Null;
r = L;//尾指针r指向头结点
for(i = 0;i < n;++i)
{
p = new LNode;
cin >> p->data;//生成新结点,输入元素值
p->next = NULL;
r->next = p;//插入到表尾
r = p;//r指向新的尾结点
}
}
//正位序输入n个元素的值,建立带表头结点的单链表L
DestroyList(&L)
DestroyList(&L)
{
}
//初始条件:线性表L已经存在
//操作结果:销毁线性表L
ClearList(&L)
ClearList(LinkList &L)
{
LinkList *p,*q;
p=L->next;
while(p)
{
q = p->next;
delete p;
p = q;
}
L->next = NULL;
return OK;
}
//初始条件:线性表L已经存在
//操作结果:将线性表L重置为空表
ListEmpty(L)
ListEmpty(L)
{
}
//初始条件:线性表L已经存在
//操作结果:若线性表L为空表,则返回TRUE;否则返回FALSE
ListLength(L)
ListLength(LinkList L)
{
LinkList p;
p = L->next;
i = 0;
while(p)
{
i++;
p = p->next;
}
return 0;
}
//初始条件:线性表L已经存在
//操作结果:返回线性表L中的数据元素个数
ListDelete(&L,I,&e)
Status ListDelete(LinkList &L,int i,ElemType &e)
{
p = L; j = 0;
while(p->next && j < i - 1)
{p = p->next; ++j;}//寻找第i个结点,并令p执行那个其前驱
if(!(p->next)|| j > i - 1)return ERROR;//删除位置不合理
q = p->next;//临时保存被删结点的地址以备释放
p->next = q->next;//改变删除结点前驱结点的指针域
e = q->data;//保存删除结点的数据域
delete q;//释放删除结点的空间
return OK;
}
GetElem(L,i,&e)
Status GetElem(LinkList L,int i,ElemType &e)
{
p = L->next; j = 1;//初始化
while(p&&j<i)//向后扫描,直到p指向第i给元素或p为空
{
p = p->next;++j;
}
if(!p||j>i)
return ERROR;//第i个元素不存在
e = p->data;//获取第i个元素
return OK;
}
//初始条件:线性表L已经存在,1<=i<=ListLength(L)
//操作结果:用e返回线性表L中的第i个数据元素的值
LocateElem(L,e)
int LocateElem(LinkList L,ElemType e,compare)
{
p = L->next;j = 1;
while(p && p->data!=e)
{p = p->next; j++;}
if(p) return j;
else return 0;
}
//返回线性表L中值为e的数据元素的位置序号,查找失败返回0
LocateElem(L,e,compare)
LocateElem(LinkList L,ElemType e,compare)
{
}
//初始条件:线性表L已经存在,compare()是数据元素判定函数
//操作结果:返回L中第1个与e满足compare()的数据元素的位序。若这样的数据元素不存在则返回值为0
PriorElem(L, cur_e,&pre_e)
PriorElem(L, cur_e,&pre_e)
{
}
//初始条件:线性表L已经存在
//操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱否则操作失败; pre_e无意义。
NextElem(L, cur_e,&next_e)
NextElem(L, cur_e,&next_e)
{
}
//初始条件:线性表L已经存在。
//操作结果:若cur_e是L的数据元素,且不是第最后个,则用pext_e返回它的后继,否则操作失败, next_e无意义。
ListInsert(&L, i, e)
Status ListInsert(LinkList &L,int i,ElemType e)
{
p = L;J = 0;
whiile(p && j < i - 1)
{p = p->next; ++j;}.//寻找第i-1个结点,p指向i-1结点
if(!p || j > i - 1)return ERROR;//i大于表长+1或者小于1,插入位置非法
s = new LNode; s->data = e;//生成新结点s,将结点s的数据域置为e
s->next = p->next;//将结点s插入线性表L中
p->next = s;
return OK;
}
//初始条件:线性表L已经存在,1<=i<= ListLength(L)+1
//操作结果:在L的第i个位置之前插入新的数据元素e, L的长度加一。
ListTraverse(&L, visited())
ListTraverse(&L, visited())
{
}
//初始条件:线性表L已经存在
//操作结果:依次对线性表中每个元素调用visited()
函数结果状态码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
函数结果状态代码
typedef int Status;
typedef char ElemType;
线性表
线性表的逻辑次序和物理次序不一定相同
单链表:
结点只有一个指针域的链表,称为单链表或线性链表
双链表:
结点有两指针域的链表,称为双链表
循环链表:
首尾相连的链表称为循环链表
头指针:指向链表中第一个结点的指针
首元结点:指链表中存储第一个数据元素a1的结点
头结点:是在链表的首元结点之前附设的一个结点
表示空表:
无头结点时,头指针为空时表示空表
有头结点时,当头结点的指针域为空时表示空表
在链表中设置头结点有什么好处?
- 便于首元结点的处理
首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其它位置一致,无须进行特殊处理
- 便于空表和非空表的统一处理
无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一
链表(链式存储结构)的特点
1.结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻。
2.访问时只能通过头指针进入链表,并通过每个结点的指针域依次向后顺序扫描其余结点,所以寻找第一个结点和最后一个结点所花费的时间不等
带尾指针循环链表的合并:
LinkList Connect(LinkList Ta,LinkList Tb)
{//假设Ta,Tb都是非空的大黁换链表
p=Ta->next;//p存表头结点
Ta->next = Tb->next->next;//Tb表头连结Ta表尾
delete Tb->next;//释放Tb表头结点
Tb->next = p;//修改指针
return Tb;
}
双向循环链表:
双向链表的插入:
void ListInsert(LinkList &L,int i, ElemType e)
{//在带头结点的双向链表L中第i个位置之前插入元素e
if(!(p=GetElem(L,i)))return ERROR;
s = new LNode; s->data = e;
s->prior = p->prior; p->prior->next = s;
s->next = p; p->prior = s;
return OK;
}
双向链表的删除:
void ListDelete(LinkList &L,int i,ElemType e)
{//删除带头结点的双向循环链表L的第i个元素,并用e返回
if(!(p=GetElem(L,i)))return ERROR;
e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
return OK;
}
栈和队列
栈和队列是限定插入和删除只能在表的“端点进行的线性表”
栈
栈是仅在表尾进行插入、删除操作的线性表
表尾(即an)称为栈顶Top;表头(即a1)称为栈底Base
插入元素到栈顶的操作,称为 入栈 \color{red}{入栈} 入栈
从栈顶删除最后一个元素的操作,称为 出栈 \color{red}{出栈} 出栈
运算规则:
后进先出 \color{green}{后进先出} 后进先出
栈的一般定义
#define MAXSIZE 100
typedef struct{
SElemType *base;//栈底指针
SelemType *top;//栈顶指针
int stacksize;//栈可用最大容量
}SqStack;
InitStack(&S)
Status InitStack(SqStack &S)//初始化栈
{
S.base = new SElemType[MAXSIZE];
if(!S.base)exit(OVERFLOW);//存储分配失败
S.top = S.base;//栈顶指针等于栈底指针
S.stacksize = MAXSIZE;
return OK;
}
//操作结果:构造一个空栈S
DestroyStack(&S)
DestroyStack(&S)//销毁栈
{
if(S.base){
delete S.base;
S.stacksize = 0;
S.base = S.top = NULL;
}
return OK;
}
//初始条件:栈S已存在
//操作结果:栈S被销毁
ClearStack(S)
Status ClearStack(SqStack S){
if(S.base)S.top = S.base;
return OK;
}
StackEmpty(S)
Status StackEmpty(SqStack S)//判断S是否为空栈
{
if(S.top == S.base)
return TRUE;
else
return FALSE;
}
//初始条件:栈S已存在
//操作结果:若栈S为空栈,则返回TRUE,否则FALSE
StackLength(S)
StackLength(S)//求栈的长度
{
}
//初始条件:栈S已存在
//操作结果:返回S的元素个数,即栈的长度。
GetTop(S,&e)
GetTop(S,&e)//去栈顶元素
{
}
//初始条件:栈S已存在且非空
//操作结果:用e返回S的栈顶元素
ClearStack(&S)
ClearStack(&S)//清空栈
{
}
//初始条件:栈S已存在
//操作结果:栈S清为空栈
Push(&S,e)
Status Push(SqStack &S,SElemType e)//入栈
{
if(S.top - S.base == S.stacksize)//栈满
return ERROR;
*S.top++=e;
return OK;
}
//初始条件:栈S已存在
//操作结果:插入元素e为新的栈顶元素
Pop(%S,&e)
Status Pop(SqStack &S,SElemType &e)//出栈
{
if(S.top == S.base)
return ERROR;
e = *--S.top;
return OK;
}
初始条件:栈S已存在且非空
//操作结果:若栈不空,删除S的栈顶元素,并用e返回其值,并返回OK;否则返回ERROR
空栈条件:base == top
栈满条件:top - base == stacksize
上溢(overflow):栈已经满,又要压入元素
下溢(underflow):栈已经空,还要弹出元素栈中元素个数: top - base
链栈
链表的头指针是栈顶
不需要头结点
基本不存在栈满的情况
空栈相当于头指针指向空
插入和删除仅在栈顶处执行
InitStack(&S)
void InitStack(LinkStack &S)
{
S = NULL;
return OK;
}
//构造一个空栈,栈顶指针置为空
StackEmpty(S)
Status StackEmpty(LinkStack S)
{
if(S == NULL)return TRUE;
else return FALSE;
}
//判断链栈是否为空
Push(&S,e)
Status Push(LinkStack &S,SElemType e)//入栈
{
p = new StackNode;//生成新结点p
p->data = e;//将新结点数据域置为e
p->next = S;//将新结点插入栈顶
S = p;//修改栈顶指针
return OK;
}
Pop(&S,&e)
Status Pop(LinkStack &S,SElemType &e)//出栈
{
if(S == NULL)return ERROR;
e = S->data;
p = S;
S = S->next;
delete p;
return OK;
}
GetTop(S)
SElemType GetTop(LinkStack S)//取栈顶元素
{
if(S != NULL)
return S->data;
}
队列
队列
队列是仅在 表头 \color{red}{表头} 表头进行删除、 表尾 \color{red}{表尾} 表尾进行插入操作的线性表
运算规则:
先进先出
#define MAXQSIZE 100
Typedef struct{
QElemType *base;//初始化的动态分配存储空间
int front;//头指针
int rear;//尾指针
}SqQueue;
InitQueue(&Q)
Status InitQueue(SqQueue &Q)
{
Q.base = new QElemType[MAXQSIZE];
if(!Q.base)exit(OVERFLOW);//存储分配失败
Q.front = Q.rear = 0;//头指针尾指针置为0,队列为空
return OK;
}
int QueueLength(Q)
int QueueLength(SqQueue Q)
{
return (Q.rear - Q.front + MAXQSIZE)%MAXQSIZE;
}
EnQueue(&Q,e)
Status EnQueue(SqQueue &Q, QElemType e)//循环队列入队
{
if((Q.rear+1)%MAXQSIZE == Q.front)return ERROR;//队满
Q.base[Q.rear] = e;//新元素加入队尾
Q.rear = (Q.rear + 1)%MAXQSIZE;//队尾指针+1
return OK;
}
DeQueue(&Q,&e)
Status DeQueue(SqQueue &Q, QElemType &e)//出队
{
if(Q.front == Q.rear)return ERROR;//队空
e = Q.base[Q.front];//保存队头元素
Q.front = (Q.front + 1)%MAXQSIZE;//队头指针+1
return OK;
}
GetHead(Q)
Status GetHead(SqQueue Q)
{
if(Q.front != Q.rear)//队列不为空
return Q.base[Q.front];//返回头指针元素的值,队头指针不变
}
链队列
#define MAXQSIZE 100
typedef struct Qnode{
QElemType data;
stuct Qnode *next;
}QNode,*QuenePtr;
typedef struct{
QuenePtr front;
QuenePtr rear;
}LinkQueue;
InitQueue(&Q)
Status InitQueue(LinkQueue &Q)
{
Q.front = Q.rear =(QueuePtr)malloc(sizeof(QNode));
if(!Q.front)exit(OVERFLOW);
Q.front->next = NULL;
return OK;
}
DestroyQueue(&Q)
Status DestroyQueue(LinkQueue &Q)
{
while(Q.front)
{
p = Q.front->next;free(Q.front);Q.front = p;
}
return OK;
}//销毁链队列,从队头指针开始,一次释放所有节点
EnQueue(&Q,e)
Status EnQueue(LinkQueue &Q,QElemType e)
{
p = (QueuePtr)malloc(sizeof(QNode));
if(!p)exit(OVERFLOW);
p->data = e; p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return OK;
}
DeQueue(&Q, &e)
Status DeQueue(LinkQueue &Q,QElemType &e)
{
if(Q.front == Q.rear)return ERROR;
p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if(Q.rear == p)Q.rear = Q.front;
delete P;
return OK;
}
GetHead(Q,&e)
Status GetHead(LinkQueue Q,QElemTyoe &e)
{
if(Q.front == Q.rear)return ERROR;
e = Q.front->next->data;
return OK;
}
EnQueue(&Q, e)
Status EnQueue(LinkQueue &Q, QElemType e)
{
p = (QueuePtr)malloc(sizeof(QNode));
if(!p) exit(OVERFLOW);
p->data = e; p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return OK;
}
DeQueue(LinkQueue &Q,QElemType &e)
Status DeQueue(LinkQueue &Q,QElemType &e)
{
if(Q.front == Q.rear) return ERROR;
p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if(Q.rear == p)Q.rear = Q.front;
delete p;
return OK;
}
串
由任意字符组成的有限序列
子串:串中任意个连续字符组成的子序列(含空串和自身)
真子串:串中任意个连续字符组成的子序列(含空串,不含自身)
子串位置:子串第一个字符在主串中的位置
空格串:由一个或多个空格组成的串,与空串不同
串相等:当且仅当两个串的长度相等且各个对应位置上的字符都相同时,这两个串才是相等的
串
#define MAXLEN 255
typedef struct{
char ch[MAXLEN+1];//存储串的一维数组
int length;//串当前长度
}SString;
Index(S,T,pos)
将主串的第pos个字符和模式串的第一个字符比较
若相等,继续诸葛比较后续字符;
若不等,从主串的下一个字符起,重新与模式串的第一个字符比较
int Index_BF(SString S, SString T, int pos){
int i=pos, j=1;
while(i<=S.length && j<=T.length)
{
if(s.ch[i]==t.ch[j]){i++;j++;}//主串和子串依次匹配下一个字符
else {i=i-j+2; j=1;}//主串、字串指针回溯重新开始下一次匹配
}
if(j>=T.length)return i-T.length;//返回匹配的第一个字符下标
else return 0;//模式匹配不成功
}
KMP算法
int Index_KMP(SString S, SString T, int pos){
int i=pos, j=1;
while(i<=S.length && j<=T.length)
{
if(j==0||S.ch[i]==T.ch[j]){ i++;j++;}
else j=next[j];/*i不变,j后退*/
}
if(j>T.length) return i-T.length;
else reurn 0;
}
void get_next(SString T, int &next[]){
i=1;next[1]=0;j=0;
while(i<T.length)
{
if(j==0 || T.ch[i] == T.ch[j]){
i++;j++;
next[i] = j;
}
else
j = next[j];
}
}
void get_nextval(SString T, int &nextval[]){
i=1;nextval[1]=0;j=0;
while(i<T.length){
if(j==0 || T.ch[i] == T.ch[j]) nextval[i] = j;
else nextval[i] = nextval[j];
}
else j = nextval[j];
}
串的链式存储—-块链结构
#define CHUNKSIZE 80//块的大小
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk *next;
}Chunk;
typedef struct{
Chunk *head,*tail;//串的头指针和尾指针
int curlen;//串的当前长度
}LString;//字符串的块链结构
数组
矩阵的压缩存储
稀疏矩阵:矩阵中非零元素很少(小于5%)
树
二叉树
顺序存储
#define MAXTSIZE 100
Typedef TElemType SqBiTree[MAXSTIZE]
SqBiTree bt;
链式存储
typedef struct BiNode{
TElemType data;
struct BiNode *lchild,*rchild;
}BiNode,*BiTree;
遍历
Status PreOrderTraverse(BiTree T){
if(T==NULL)return OK;
else
{
visit(T);//fan
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
层次遍历算法:
void LevelOrder(BNode *b){
BTNode *p; SqQueue *qu;
InitQueue(qu);//初始化队列
enQueue(qu, b);//根结点指针进入队列
while(!QueueEmpy(qu)){
deQueue(qu, p);//出队结点p
printf("%c", p->data);//访问结点p
if(p->lchild!=NULL)enQueue(qu, p->lchild);
if(p->rchild!=NULL)enQueue(qu,p->rchild);
}
}
线索二叉树
如果某个结点的左孩子为空,则将空的左孩子指针域改为指向其前驱;
如果某个结点的右孩子为空,则将空的右孩子指针域改为指向其后继;
新增两个标志域ltag和rtag,bin并约定:
ltag = 0 lchild 指向该结点的左孩子
ltag = 1 lchild 指向该结点的前驱
ltag = 0 lchild 指向该结点的右孩子
ltag = 1 lchild 指向该结点的后继
typedef struct BiThrNode{
int data;
int ltag, rtag;
struct BiThrNode *lchild, rchild;
}BiThrNode,*BiThrTree;
森林
是 m(m >= 0) 棵互不相交的树的集合
typedef struct PTNode{
TElemType data;
int parent;
}PTNode;
#define MAX_TREE_SIZE 100
typedef struct{
PTNode nodes[MAX_TREE_SIZE];
int r, n;//根节点位置和结点个数
}PTree
哈夫曼树
typedef struct{
int weight;
int parent,lch,rch;
}HTNode,*HuffmanTree;
void CreatHuffmanTree(HuffmanTree HT, int n)//构造哈夫曼树——哈夫曼算法
{
if(n<=1)return;
m=2*n-1;//数组共2n-1个元素
HT = new HTNode[m+1];//0号单元未用,HT[m]表示根结点
for(i=1;i<=m;i++)
{
HT[i].lch=0;
HT[i].rch=0;
HT[i].parent = 0;
}
for(i=1;i<=n;i++)
cin >> HT[i].weight;
}//初始化
for(i=n+1;i<=m;i++)//合并产生n-1个结点
{
Select(HT,i-1,s1,s2);//在HT[k](1<=k<=i-1)中选择两个其双亲域为0
//且权值最小的结点,并返回他们在HT中的序号s1和s2
HT[s1].parent = i;
HT[s2].parent = i;//从F中删除s1 s2
HT[i].lch = s1;
HT[i].rch = s2;//s1,s2分别作为i的左右孩子
HT[i].weight = HT[s1].weight + HT[s2].weight;//i的权值为左右孩子的权值之和
}
void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)//从叶子到根你想求每个字符的哈夫曼编码,存储在编码表HC中
{
HC = new char *[n+1];//分配n个字符编码的头指针矢量
cd =new char [n];//分配临时存放编码的动态数组空间
cd[n-1] = '\0';//编码结束符
for(i=1;i<=n;i++)
{
start = n-1;
c=i;
f=HT[i].parent;
while(f!=0)//从叶子结点开始向上回溯,直到根结点
{
--start;//回溯一次start向前指一个位置
if(HT[f].lchild == c)
cd[start]= '0';//结点c是f的左孩子,则生成代码0
else
cd[start]= '1';//结点c是f的右孩子,则生成代码1
c=f;
f=HT[f].parent;//继续向上回溯
}//求出第i个字符的编码
HC[i]=new char [n-start];//为第i个字符串编码分配空间
strcpy(HC[i], &cd[start]);//将求得的编码从临时空间cd赋值到HC的当前行中
}
delete cd;
}
图
邻接矩阵
#define Maxlnt 32767 //表示极大值,即正无穷
#define MVNum 100 //最大顶点数
typedef char VerTexType; //设顶点的数据类型为字符串
typedef int ArcType; //设边的权值类型为整型
typedef struct{
VerTexType vexs[MVNum]; //顶点表
ArcType arcs[MVNum][MVNum]; //邻接矩阵
int vexnum,arcnum; //图的当前点数和边数
}AMGraph;
创建无向网
Status CreateUDN(AMGraph &G){
//采用邻接矩阵表示法,创建无向网G
cin >> G.vexnum >> G.arcnum;//输入总项顶点数 总边数
for(i = 0; i < G.vexnum; i++)
cin >> G.vexs[i]; //依次输入点的信息
for(i = 0; i < G.vexnum; i++) //初始化邻接矩阵
for(j = 0; j < G.vexnum; j++)
G.arcs[i][j] = Maxlnt; //边的权值均为极大值
for(k = 0; k< G.arcnum; k++)//构造邻接矩阵
{
cin >> v1 >> v2 >>w; //输入一条边所依附的顶点及边的权值
i = LocateVex(G, v1);
j = LocateVex(G, v2); //确定v1和v2在G中的位置
G.arcs[i][j] = w; //边<v1, v2>的权值为w
G.arcs[j][i] = G.arcs[i][j];//置<v1, v2>的对称边<v2, v1>的权值为w
}
return OK;
}
查找顶点
int LocateVe(AMGraph G, VertexType u){
//在图中查找顶点u在顶点表中的下标
int i;
for(i = 0; i < G.vexnum; i++)
if(u == G.vexs[i]) return i;
return -1;
}
邻 接表
typedef struct VNode{
VerTexType data; //顶点信息
ArcNode *firstarc;//指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum];//AdjList表示邻接表类型
#define MVNum 100 //最大顶点数
typedef struct ArcNode{ //边结点
int adjvex; //该边所指向的顶点的位置
struct ArcNode * nextarc;//指向下一条边的指针
Otherlnfo info;//和边相关的信息
}ArcNode;
typedef struct{
AdjList vertices;//vertices--vertex的复数
int vexnum,arcnum;
}ALGraph;
创建无向网
Status CreateUDG(ALGraph &G){ //采用邻接表表示法,创建无向图G
cin> >G.vexnum> >G.arcnum; //输入总顶点数,总边数
for(i = O; i<G.vexnum; ++i){ //输入各点,构造表头结点表
cin>> G.vertices[i].data; //输入顶点值
G.vertices[i].firstarc=NULL; //初始化表头结点的指针域}//for
for(k = O; k<G.arcnum;++k){ //输入各边,构造邻接表
cin>>v1> >v2; //输入一条边依附的两个顶点
i = LocateVex(G, v1);
j = LocateVex(G, v2);
p1=new ArcNode; //生成一个新的边结点*p1
p1->adjvex=j; //邻接点序号为j
p1->nextarc= G.vertices[i].firstarc;
G.vertices[i].firstarc=p1;//将新结点*p1插入顶点vi的边表头部
p2=new ArcNode;
p2->adjvex=i; //邻接点序号为i
p2->nextarc= G.vertices[j].firstarc;
G.vertices[j].firstarc=p2;//将新结点*p2插入顶点vj的边表头部
}//for
return OK;
十字链表
邻接多重表
图的遍历
深度优先遍历
在访问图中某一起始顶点v后,由v出发,访问它的任一邻接顶点w;
再从W出发,访问与w邻接但还未被访问过的顶点W2;
然后再从W2出发,进行类似的访问,…
如此进行下去,直至到达所有的邻接顶点都被访问过的顶点u为止。接着,退回一步,退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。
如果有,则访可此顶点,之口再从此顶点出发,进行与前述类似的访问;
如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止。
void DFS(AMGraph G, int v)//图G为邻接矩阵类型
{
cout << v; visited[v] = true;//访问第v个顶点
for(w = 0;w < G.vexnum; w++)//依次检查邻接矩阵v所在的行
if((G.arcs[v][w]!=0)&&(!visited[w]))
DFS(G,w);//w是v的邻接点,如果w未访问,则递归调用DFS
}
广度优先遍历
void BFS (Graph G, intv)//按广度优先非递归遍历连通图G
{
cout<sv; visited[v] =true;//访问第v个顶点
lnitQueue(Q);//辅助队列Q初始化,置空
EnQueue(Q, v);//v进队
while(!QueueEmpty(Q)){//队列非空
DeQueue(Q, u);//队头元素出队并置为u
for(w = FirstAdjVex(G,u); w> =O; w = NextAdjVex(G, u, w))
if(!visited[w])//w为u的尚未访问的邻接顶点
{
cout<<w; visited[w] = true; EnQueue(Q, w);//w进队
}//if
}//while
}//BFS
Prim(普里姆)算法
算法思想:
设N=(V,E)是连通网,TE是N上最小生成树中边的集合。
初始令U={u0},(uo ∈ V),TE={ }。
在所有u∈U, v∈ V-U的边(u, v)∈E中,找一条代价最小的边(uo,vo)。
将(uo,vo)并入集合TE,同时vo并入U
重复上述操作直至U=V为止,则T=(V,TE)为N的最小生成树。时间复杂度:O(n^2)
克鲁斯卡算法
算法思想:
设连通网N = (V,E),令最小生成树初始状态为只有n个顶点而无边的非连通图T=(V.{ }),每个顶点自成一个连通分量。
在E中选取代价最小的边,若该边依附的顶点落在T中不同的连通分量上(即:不能形成环),则将此边加入到T中;否则,舍去此边,选取下一条代价最小的边。
依此类推,直至T中所有顶点都在同一连通分量上为止。时间复杂度:O(eloge)(e为边数)
Dijistra算法
T中顶点对应的距离值用辅助数组D存放。
D[i]初值:若<Vo, Vi>存在,则为其权值;否则为∞。
从T中选取一个其距离值最小的顶点Vj,加入S。
对T中顶点的距离值进行修改:若加进Vj作中间顶点,从Vo到Vi的距离值比不加Vj的路径要短,则修改此距离值。
重复上述步骤,直到S=V为止。
查找
typedef struct{
KeyType key;//关键字域
.... //其他域
}ElemType;
typedef struct {//顺序表结构类型定义
ElemType *R;//表基址
int length;//表长
}SSTable;
SSTable ST;
int Search_Seq(SSTable ST, KeyType key){
//若成功返回其位置信息,否则返回0
for(i=ST.length;i>=1;i--)
if(ST.R[i].key == key) return i;
return 0;
}
二分查找
int Search_Bin ( SSTable ST,KeyType key ) {
low = 1 ; high = ST.length ;//置区间初值
while (low <= high)
{
mid = (low + high)/ 2;
if (ST.R[mid].key == key)return mid ;//找到待查元素
else if (key <ST.R[mid].key)//缩小查找区间
high=mid-1;//继续在前半区间进行查找
else low = mid + 1;//继续在后半区间进行查找
}
return 0;//顺序表中不存在待查元素
} //Search_Bin
效率:O(log2 n)
二叉排序树
typedef struct{
KeyType key;//关键字项
InfoType otherinfo;//其他数据域
}ElemType;
typedef struct BSTNode{
ElemType data; //数据域
struct BSTNode *lchild, *rchild; //左右孩子指针域
}BSTNode, *BSTree;
BSTree T;//定义二叉排序树T
BSTree SearchBST(BSTree T,KeyType key){
if((!T)||key == T->data.key)return T;
else if(key < T->data.key)
return SearchBST(T->lchild,key);//在左子树中继续查找
else return SearchBST(T->rchild,key);//在右子树中继续查找
}//