知识点盲区
主要为在做题过程中发现的知识点盲区,自己的找到的坑,逐步一点一点慢慢的填上
 0.1 队列
 顺序队列空:frontrear
 顺序队列满:frontrear,会出现假溢出情况
 因为顺序队列是按照头出尾进的操作方式存储元素,当元素存满队列,从队头出队元素到队列非空,在执行入队列操作时,队列实际上是没有满,还有大量的空闲元素,但是已经满足rear==frot的条件,我们把这种现象叫做假溢出,为了解决这种问题引出了循环队列的概念。
初始时:front=rear=0
 循环队列入队:rear=(rear+1)%MAXSIZE
 循环队列出队:front=(front+1)%MAXSIZE
 循环队列长度:(rear-front+MAXSIZE)%MAXSIZE
 循环队列队空:frontrear
 循环队列队满:
 (1)牺牲一个单元来区分队空或队满,入队列时候少用一个队列单元
 队满:(rear+1)%MAXSIZEfront
 队空:front=rear
 元素个数:(rear-front+MAXSIZE)%MAXSIZE
 (2)增加一个元素表示数据成员个数,
 队满:sizeMAXSIZE,frontrear
 队空:size0,frontrear
 (3)增加tag数据成员,区分队空还是满
 tag0时,若因删除导致frontrear,则为空
 tag1时,若因插入导致frontrear,则为满
0.2 链队列
 不带头结点的队列front指向第一个元素,rear指向最后一个元素,当队列空时rear=front=null
 带头结点的队列front指向头结点,rear指向最后一个元素,当队列空时,rear、front都指向头结点
void InitQueue(LinkQueue *Q)
{
		Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
		Q.front->next = NULL;
}
bool IsEmpty(LinkQueue Q)
{
		if(Q.front == Q.rear)
				return true;
		else
				return false;
}
void EnQueue(LinkQueue &Q,ElemType x)
{
		LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
		s->data = x;
		s->next = NULL;
		Q.rear->next = s;
		Q.rear = s;
}
void DeQueue(LinkQueue &Q,ElemType &x)
{
		if(Q.front == Q.rear)
				return false;
		x = p->data;
		Q.front->next = p->next;//指向出队元素的后一个
		if(Q.rear == p)
				Q.rear = Q.front;
		free(p);
		return true;
}
0.3 双端队列
 双端队列是指两端都可以进行插入和删除操作的队列
 输出受限的双端队,允许在一端进行插入和删除,另外一端只允许插入
 输入受限的双端队,允许在一端进行插入和删除,另外一端值允许删除
1、线性表的基本操作
 线性表的操作都是从第i个位置,而不是下标,
 插入元素需要后移动n-i+1
 删除元素需要移动n-i
 查找元素i
 2、已知邻接矩阵,计算i结点的入度,删除所有i结点出发的狐头
 邻接矩阵行是出度,列是入度
 删除i结点出发的边,将邻接矩阵中i行的元素都置为0即可删除边
有向图的邻接矩阵i行是出度,j列是入度,度是顶点入度和出度之和
 无向图的邻接矩阵i行或j列为某个结点的度,
3、二叉排序树的中序遍历是递增序列
 (1)非空二叉树上的叶子结点数等于度为2的结点数加1:n0=n2+1
 (2)非空二叉树上第k层至多有2^(k-1)个结点
 (3)高度为h的二叉树至多有2^h-1个结点
 (4)高度为log2n+1
 1)当i>i时,结点i的双亲结点编号为i/2,当i为偶数时,双亲为n/2,是左孩子,当i为奇数时,双亲为(i-1)/2,是右孩子
 2)当2i<=n时,结点i的左孩子编号为2i,否则无左孩子
 3)当2i+1<=n时,结点i的右海子编号为2i+1,否则无右孩子
 4、拓扑排序的作用
 判断有向图是否有环路,求有向图的最长路径
 5、数据结构的逻辑结构
 三对角矩阵
 前n-1行有:3(n-2)+2=3i-4个元素
 第n行aij元素前有多少个元素:(j-i)+1
 第
6、广义表转化为树
 根据广义表构建二叉树
 7、排序的插入次数
 最好情况下,序列已经有序,每次选取递增序列进行比较,不需要移动元素,时间复杂度为O(n)
 最坏情况下,序列逆序,每次都要比较,每次都要移动,比较2+3+…+n次,移动i+1次,哨兵操作两次,移动元素i-1次
 稳定性,由于每次插入元素从事从后向前先比较在移动,所以不会发生位置变化
折半插入的比较次数
 折半插入仅仅减少了比较次数O(nlog2n),时间复杂度还是O(n2)
冒泡排序
 最好情况下,序列有序,第一趟检测到有序后flag为false则表明没有元素交换,从而直接退出,比较n-1次,移动0次,时间复杂度为O(n)
 最坏情况下,序列逆序,进行n-1趟排序,第i趟排序进行n-i次比较,每次比较后移动3次交换元素Swap函数,
 进行n-1趟比较,比较n-i次,移动3(n-i)次,时间复杂度为O(n2)
 稳定性,当i>j时且A[i] == A[j]时不会发生交换,稳定排序,产生的序列是全局有序的
快速排序
 最好情况下,元素基本逆序,递归树平衡,时间复杂度O(n2),空间复杂度O(log2n)
 最坏情况下,元素在两个取于分别是n-1个和0个元素,元素基本有序,时间复杂度O(n2),空间复杂度O(n)
 稳定性,在划分过程中,若区间内有小于基准的值,则在交换过程中相对位置会发生变化
 排序后不会产生有序子序列,但是每趟排序后基准元素会被放在最终位置
选择排序
 最好情况下,序列有序,比较n趟,比较i次(找最小元素),共n(n-1)/2次
 最坏情况下,序列无序,比较n趟,比较i次,共n(n-1)/2次,因此时间复杂度始终为O(N2)
 稳定性,在第i趟找最小元素后,可能会导致相同关键字元素的相对位置发生改变,因此是不稳定算法
堆排序
 调整时间与树高有关,在n个元素的堆中,比较次数不超过4n,比较的时间复杂度为O(n)
 建堆的时间为O(n),调整n-1次,每次O(h),h为树高,故时间复杂度为O(nlog2n)
 适合于关键字特大的情况,不稳定,因为构建堆的过程中可能会交换相对位置
归并排序
 算法思想,按照2,4,8,16,…,的间隔不断将多个有序子列表进行合并排序。
 最好情况下,每趟的时间复杂度为O(n),需要进行log2n趟,故时间复杂度为O(nlog2n)
基数排序
 将插入的记录按照插入顺序连接起来。
 空间效率,一趟排序需要辅助空间为r(r个队列),O®,r个关键字,d表示数字最大的位数
 时间效率,基数需要进行d趟分配和收集,一趟分配需要O(n),一趟收集需要O®,一趟的时间复杂复杂度为O(n+r),时间复杂度为O(d(n+r))。
 8、堆的性质,建立,调整,插入
大根堆、小根堆:堆顶的元素都比双亲大或小,是完全二叉树
 堆的建立,根据序列按照层序填充,插入的元素在最后
 堆的调整,堆[n/2]-1个结点不断调整
9、哈夫曼树的性质
 10、哈夫曼树的叶子结点的个数
 11、二分查找的判定树的高度
 log2n+1
 12`、满二叉树
 除了叶子结点外,每个结点的度都为2,左孩子结点为n/2,右孩子结点为2i+1
 12、完全二叉树的性质
 (1)i<n/2,则结点i为分支结点,否则为叶子结点
 (2)叶子结点只可能在最大的两层数先,对于最大层次中的叶子结点,都依次排到该层的最左边
 (3)若有度为1的结点,则只可能有1个,且该结点只有左孩子,没有右孩子
 (4)按照层序编号,一旦出现某结点为叶子结点或只有左孩子,则编号大于i的结点均为叶子结点
 (5)n为奇数时,每个分支结点都有左孩子和有孩子,n为偶数时编号最大的分支结点(n/2)只有左孩子,没有右孩子
 13、冒泡排序的比较次数
 冒泡排序
 最好情况下,序列有序,第一趟检测到有序后flag为false则表明没有元素交换,从而直接退出,比较n-1次,移动0次,时间复杂度为O(n)
 最坏情况下,序列逆序,进行n-1趟排序,第i趟排序进行n-i次比较,每次比较后移动3次交换元素Swap函数,
 进行n-1趟比较,比较n-i次,移动3(n-i)次,时间复杂度为O(n2)
 稳定性,当i>j时且A[i] == A[j]时不会发生交换,稳定排序,产生的序列是全局有序的
 14、二分查找的平均查找长度
 二叉排序树为平衡二叉树则高度为O(log2n),若为单只树(变成了链表)则为O(n)
二叉排序树生成树不唯一,当序列不同时树不同,二分查找的树唯一
 15、三维数组的存储地址
 16、关键路径的相关概念理解
 AOE网特性:
 (1)只有在某顶点所代表的事件发生后,从该顶点出发的各有向边代表的活动才能开始。
 (2)只有在进入某顶点的各个有向边所代表的活动都结束时,该顶点所代表的事件才能发生
 (3)AOE网中仅有一个入度为0的顶点,称为源点,表示整个工程的开始,仅仅有一个出度为0的点,称为汇点
 从源点到汇点的路径中,具有最大长度的路径称为关键路径,关键路径上的活动称为关键活动。
 完成整个工程的最短路径就是关键路径的长度,即关键路径上活动花费开销和,因为关键活动影响了工程的事件,若关键活动不按时完成,则会影响工程的完成时间
 关键活动相关概念
 1)事件最早发生事件ve
 从前往后取最大,决定了所有v开始活动的最早时间,max
 2)事件最晚发生事件vl
 从后往前取最小,决定了所有v开始活动最迟发生时间,min
 3)活动最早开始时间e
 该弧 起点 表示的事件,最早发生时间,<k,j>表示边i,e(i)=ve(k)
 4)活动最迟开始时间l
 该弧 终点 表示的事件,最迟发生时间与该活动所需要时间的差,<k,j>表示边i,l(i)=vl(j)-weight(i)
 5)最迟开始时间和最早开始时间差d
16.1、最短路径相关概念
 单源最短路径:dijkstra,不适用带有负值的图,因为最短路径长度加上这条负值的俄结果可能小于a原先确定的最短路径长度,则无法进行更新。
 时间复杂度:邻接矩阵,为O(v^2)
 16.2、拓扑排序
 有向图的无环图的排序
 (1)每个顶点只出现一次
 (2)若顶点A在序列中排在顶点B前面,则在图中不存在顶点B到顶点A的路径
 拓扑排序是对有向无环图的一种排序,使得若存在一条边从顶点A到顶点B的路径,在排序中顶点B出现在顶点A的后面
bool Topological(Graph G)
{
		InitStack(s);
		for(int i = 0;i < G.vexnum;i++)
		{
				if(indegree[i] == 0)//将所有入度为0的结点入栈
						push(s,i);
		}
		int count = 0;
		while(!IsEmpty(s))//DFS思想
		{
				pop(s,i);//出栈
				print[count++] = i;//访问
				for(p = G.vertices[i].firstarc;p >= 0;p = p ->nextarc)//所有指向i的顶点入度减1,如果减完后的顶点度为0则入栈。
				{
						v = p->adjvex;
						if(!(--indegree[v]))//入度为0则入栈
						{
								push(s,v);
						}
				}
		}
		if(count < G.vexnum)
				return false;
		else
				return true;
}
bool Topo(Graph G)
{
		InitStack(s);
		for(i = 0;i < G.vexnum;i++)
		{
					if(indegree[i] == 0)
					{
								push(s,i);
					}	
		}
		int count = 0;
		while(!IsEmpty(s))
		{
					pop(s,i);
					print[count++] = i;
					for(w = FirstNeighbor;w >= 0;w = NextNeighbor(G,w,v))
					{
								if(!(--indegree[v]))
										push(s,v);
					}
		}
		if(count < G.vexnum)
				return false;
		else
				return true;
}
17、二叉树空链域的问题
n个结点的二叉链表中有n+1个空链域,n个结点有2n域,除了根结点外每个结点都被指向故有n-1个被占用
 空=2n-(n-1)=n+1个
18、顺序查找的查找长度
 查找成功:每个元素的比较次数n-i+1次,共n个元素,每个元素查找概率为1/n,(1+2+…+n)1/n,ASL=(n+1)/2
 查找失败:每个元素比较次数为n+1次,ASL=n+1
有序表的顺序查找
 n个结点,有n+1个查找失败的结点,n+1空指针域
 除了第一个结点以外每个结点都有指针值指向该结点2n-(n-1)=2n-n+1=n+1个空指针域
查找成功:每个元素比较n-i+1次,共n个元素,每个元素查找概率为1/n,(1+2+…+n)1/n,ASL=(n+1)/2
 查找失败:查找失败次数等于父圆形结点所在层数,最后一层有2个查找失败结点
 每个查找失败的概率为1/(n+1),(1+2+…+n+n)/n+1=n/2 + n/(n+1)

**18.2、折半查找 **
int Binary_Search(SeqList L,ElemType key)
{
		int low = 0,high = L.len-1,mid;
		while(low <= high)
		{
				mid=(low+high)/2;
				if(L.elem[mid] == key)
						return mid;
				else if(L.elem[mid] > key)
						high = mid - 1;
				else
						low = mid + 1;
		}
		return -1;
}
n个元素,判定树有n个圆形结点和n+1个非圆形结点,是一棵平衡二叉树
 查找成功:查找长度为根结点到目的结点路径上结点个数,也就是层高
 查找失败:查找失败为根结点到目的结点上父亲结点个数,也就是层高
 查找成功平均查找长度ASL=1/n(11+22+…+h2^h-1)=n+1/n log2(n+1) = log2(n+1) - 1=树高(多种表示方法)
 时间复杂度为O(log2n)
 查找成功平均查找长度ASL=(园形结点个数层数)/方形结点个数
 查找失败平均查找长度ASL=(方形结点个数*层数)/方形结点个数
 18.3、分块查找
 分块查找:块内无序,块间有序
 第一块中的最大关键字小于第二块中所有关键字,
 第二块中的最大关键字小于第三块中所有关键字。。
 索引表,索引表中有每个元素块中的最大关键字和各个块的第一个元素地址,索引表有序排列
 平均查找长度ASL=L1+Ls
将长度为n的查找表均匀的分成b块(索引表),每块s的元素(块内),此时b和s相当于n
 块内和索引在表中都采用顺序查找: ASL=L1+l2=(b+1)/2 + (s+1)/2
 快内采用顺序查找、索引表采用折半查找:ASL=L1+Ls = log2(b+1) + (s+1)/2
 19、三元组相关概念
 20、k叉树的性质
 树的基本性质:
 (1)树中结点数等于所有结点度数之和+1
 (2)度为m的树中第i层上最多有m^(i-1)个结点
 (3)高度为h的m叉树中最多有(m^k - 1)/(m-1)个结点
 (4)具有n个结点的m叉树最小高度为logm(n(m-1))+1
总结点数=n0+n1+n2+…+nm
 总分支数=0n0+1n1+2n2+mnm(度为m的结点引出m条分支)
 总结点数=总分支数+1
 20、哈夫曼树
 哈夫曼树中只有度为0和度为2的结点
 度为m的哈夫曼树只有度0和m的结点,设度为m的结点有nm个,度为0的结点有n0个,结点总数为n,n=n0+nm
 n个结点的哈夫曼树有n-1条分支,mn = n-1=nm+n0-1,整理得(m-1)nm=n0-1,nm=(n-1)/(m-1)
特点
 (1)初始结点都为叶子结点,权值越小根根结点的路径月长
 (2)构造过程中新建了n-1个结点(双分支结点),哈夫曼树结点总数为n+n-1=2n-1
 (3)每次构造都选择两个树作为新的结点,因此不存在度为1的结点,只有度为0和2的结点
 21、散列表的性质,k如何取值
 散列函数可能会把两个或两个以上的不同关键字映射到同一地址,称这种情况为冲突,这些发生冲突的不同关键字称为同义词,这些冲突不可避免。
 散列函数的构造
 (1)散列函数定义域必须包括需要存储的关键字,值域的范围
 (2)散列函数计算出来的地址应该能等概率、均匀的分布在整个地址空间,从而减少冲突
常见的散列函数:
 (1)直接定址法:适合关键字分布基本连续的情况
 (2)除留余数法:散列表的长度为m,取一个不大于m但接近或等于m的质数
 (3)数字分析法
 (4)平方折中法
处理冲突的方法
 (1)开放地址法
 1)线形探测
 平均查找长度
 ASL成功 =(比较次数*关键字个数)/总关键字个数
 ASL失败 =(查找失败次数 * 关键字个数)/p的查找个数,地址的范围为p的取值范围
2)平方探测
 3)在散列法
4)伪随即法
 (2)拉链法
 平均查找长度
 ASL成功 =(关键字的位置*关键字的个数)/总关键字个数
 ASL失败 =(查找失败次数 * 关键字个数)/p的查找个数(表长吗,答不是),地址的范围为p的取值范围
 对于每一个同义词进行查找,
装填因子a=表中记录n/三列表长度m,
 平均查找长度依赖于装填因子,不直接依赖于m和n,装填因子越大,表示记录越满,发生冲突可能性越大

 https://blog.csdn.net/u011080472/article/details/51177412

22、各种排序的性质,时间复杂度,与初始序列是否有关
 23、图的十字链表法、三元组、多重链表的画法
 邻接表
 以某个结点为起点,每个结点依次指向与其相连的顶点
#typedef MaxVerterNum 100
typedef struct ArcNode//边表结点
{
		int adjvex;//邻接点域
		struct ArcNode *next;//指针域
}ArcNode;
typedef struct VNode//顶点表结点
{
		VertexType data;//数据域
		ArcNode *first;//边表头指针
}VNode,AdjList[MaxVertexNum];
typedef struct
{
		AdjList vertices;//邻接表
		int vexnum,arcnum;
}ALGraph;//图
邻接表特点
 (1)若图G为无向图,需要的空间为O(V+2E),因为不区分方向,只要有相邻的边就表示出来,若G为有向图,需要空间为O(V+E)。
 (2)给定一定的点,很容易找到所有的边,为O(n),但是要找到顶点之间是否存在边,邻接表为O(n^2)
 (3)有向图的邻接矩阵,出度为邻接表的结点个数,求入度需要遍历整个表。无向图,为顶点的个数
十字链表法
 弧结点:[tailvex][headvex][hlink][tlnik][infor]
 taillvex:尾弧结点
 headvex:头弧结点
 hlink:指向头相同的下一条边
 tlink:指向尾相同的下一条边
 顶点结点:[data][firstin][firstout]
 firstin:第一条入度边
 firstout:第一条出度边
 
可以方便的求出度和入度信息,但是删除麻烦
 邻接多重表
 边表:[mark][ivex][ilink][jvex][info]
 ilink:指向下一条依附于ivex的边,相同尾巴
 jlink:指向下一条依附于顶点jvex的边,相同头
 
24、数据结构相关的基础概念
 25、树和二叉树的区别、性质
 26、二叉树的平衡调整
 二叉树调整笔记
27、二叉线索树
中序线索化创建
 1、如果左子树为空,建立前驱线索
 2、如果pre不为空且pre的右孩子为NULL,建立前驱结点的后继线索
 pre标记刚刚访问过的结点
void InTread(ThreadTree &p,ThreadTree &pre)
{
		if(p != NULL)
		{
				InThread(p->lchild,pre);
				if(p->lchild == NULL)
				{
						p->lchild = pre;
						p->ltag = 1;
				}
				else
				{
						p->ltag = 0;
				}
				if(pre != NULL && pre->rchild == NULL)
				{
							pre->rchild = p;
							pre->rtag=1;
					}
					else
					{
							p->rtag=0;
					}
					pre = p;
					InThread(p->rchild,pre);
		}
}
void preTread(ThreadTree &p,ThreadTree &pre)
{
		if(p != NULL)
		{
				if(p->lchild != NULL)
				{
						p->lchild = pre;
						p->ltag = 1;
				}
				else
				{
						p->ltag=0;
				}
				if(pre != NULL && pre->rchild == NULL)
				{
							pre->rchild=p;
							pre->rtag = 1
				}
				else
				{
							pre->ltag = 0;
				}
				pre = p;
				
		}
}
ThreadNode *FirstNode(ThreadNode *p)
{
		while(p->ltag == 0)
				p = p->lchild;
		return p;
}
ThreadNode *NextNode(ThreadNode )
{
		if(p->rtag == 0)//如果p右子树没有线索,则找右子树中的第一个结点就是他的后继
				return FistNode(p->rchild);
			else
				return p->child;
}
void Inorder(ThreadNode *T)
{
		for(ThreadNode *p = FistNode(T);p != NULL;p = NextNode(p))
				visit(p);
}
BDAEC
DBEACG

 中序线索二叉树
 1、查找p的前驱:查找左线索,若无左线索,结点的前驱是遍历左子树访问的最后一个结点
 2、查找p的后继,查找右线索,若无右线索,结点的后继是遍历右子树访问的第一个结点。
 29、树与二叉树、森林的转换
 (1)树转二叉树
 兄弟相连,留长子
 1)加线,在所有兄弟结点之间加线
 2)去线,树中的每个结点,只保留与它与第一个孩子结点的连线,删除与其他孩子结点之间的连线
 3)层次调整
 
(2)森林转为二叉树
 去掉全部右孩线,孤立二叉在还原
 1)把每棵树转为二叉树
 2)第一棵树不动,从第二棵树开始,依次把根结点作为前一棵二叉树的根结点的右孩子,连接起来
 
(3)二叉树转树
 左孩右右连双亲,去掉原来右孩线
 
 (4)森林转为二叉树
 树变二叉根相连
 
 二叉树、森林的转换
30、二叉排序树的删除
 (1)若被删除的结点z是叶子结点,则直接删除
 (2)若被删除的结点z只有一颗左子树或者右子树,则让z的子树称为z父结点的子树,代替z的位置
 (3)若被删除的结点z有左右两棵子树,则令z的直接后继代替z,然后从二叉排序树中删除这个直接后继或者直接前驱,变成了第一二情况
 
 31、二叉排序树平均查找长度
 二叉排序树查找效率取决于树的高度,若二叉排序树为平衡二叉树则高度为O(log2n),若为单只树(变成了链表)则为O(n)
二叉排序树生成树不唯一,当序列不同时树不同,二分查找的树唯一
 32、图的边、顶点、度
 简单路径:路径中,顶点不重复出现的路径称为简单路径。
 简单回路:除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路称为简单回路。
 完全图,无向图有n(n-1)/2条边,任意两个顶点之间都存在边,有向图有n(n-1)条边,任意两个顶点之间都存在方向相反的弧
 无向图,n个顶点有n-1条边,构成一个完全图,则为最小连通图,若多余n-1则为回路
 有向图,n个顶点至少n条边,构成一个环路
若一个图有n个顶点,并且有大于n-1条边,则一定有环
 33、BFS相关
 BFS类似树的层序遍历
 生成树不唯一
 采用邻接表存储,每个顶点均被搜索入队一次,时间复杂度为O(V),在搜索邻接顶点时每条边至少被访问一次,时间复杂度为O(E),总的时间复杂度为O(V+E)
 采用邻接矩阵存储,查找每个顶点的邻接点需要O(V),故需要O(V^2)
bool BFSTraverse(Graph G)
{
		for(i = 0;i < G.vexnum;++i)
		{
				visited[i] = False;
		}
		InitQueue(Q);
		for(i = 0;i < G.vexnum;++i)
		{
				if(!visited[i])
				{
						BFS(G,i);
				}
		}
}
void BFS(Graph G,int v)
{
		visit(v);//访问v
		visited[v] = True;//数组置为1
		EnQueue(Q,v);//入队列
		while(!IsEmpty(Q))//如果队列不空
		{
				DeQueue(Q,v);//出队列
				for(w = FirstNeighbor(G,v);w >= 0;w = NextNeighbor(G,v,w))//查找v相邻的边
				{
							if(!visited[i])//如果不空
							{
									visit(w);//访问
									visited[w] = True;
									EnQueue(Q,w);//入队
							}
				}
		}
}
//BFS求单源最短路径
void BFS_MIN_Distance(Graph G,int u)
{
		for(i = 0;i < G.vexnum;++i)
		{
				d[i] = #;
		}
		EnQueue(Q,u);
		while(!Isempty(Q))
		{
				DeQueue(Q,u);
				for(w = FirstNeighbor(G,u);w >= 0;w = NextNeighbor(G,u,w))
				{
						if(!visited[w])
						{
								visited[w] = True;
								d[w] = d[u]+1;//如果有路径则+1
								EnQueue(Q,w);
						}
				}
		}
}
33、DFS
 DFS类似于树的先序遍历
 DFS生成树和生成森林不唯一
void BFSTravers(Graph G)
{
		for(v = 0;v < G.vexnum;++v)
		{
				visit[v] = FAlse;
		}
		for(v = 0;v < G.vexnum;++v)
		{
				if(!visited[v])
						DFS((G,v);
		}
}
void DFS(Graph G,int v)
{
		visit(v);
		visited[v] = True;
		for(w = FirstNeighbor(G,v);w >= 0;w = NextNeighbor(G,v,w))
		{
				if(!visited[w])
				(
						DFS(G,w);
				)
		}
}
void DFS1(Graph G,int v)
{
		InitStack(S);
		visit(v);
		visited[v] = True;
		push(S,v);
		while(!IsEmpty(S))
		{
					pop(S,v);//出栈以后访问
					visit(v);
					for(w = FirstNeighbor(G,v);w >= 0;w = Neighbor(G,v,w))
					{
						if(!visited[w])
						{
								push(S,w);
								visited[w] = True;//每次进栈都要置为1
							}
					}
		}
}










