数据结构
数据结构
树,图
二叉树遍历
非递归前序遍历
利用栈来实现遍历,在每次将节点压入栈时访问也就是只要到当前节点就访问。
然后访问左子树,然后右子树。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| do{ while(p!=NULL) { push_s(p);//压入栈访问 printf("%c ",p->data); p=p->lchild;//指向左子树 } if(!empty_s()) { p=pop_s(); p=p->rchild;//指向右子树 }
}while(!empty_s()||p!=NULL);//栈不空或者节点不为NULL
|
非递归中序遍历
中序遍历只需要改变打印输出的位置就可以了,在出栈时打印。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| do{ while(p!=NULL) { push_s(p);//压入栈访问
p=p->lchild;//指向左子树 } if(!empty_s()) { p=pop_s(); printf("%c ",p->data);//在pop后打印节点值 p=p->rchild;//指向右子树 }
}while(!empty_s()||p!=NULL);//栈不空或者节点不为NULL
|
非递归后序遍历
后续遍历比较复杂,需要根节点的左右子树均被访问后,才可以访问根节点。
所以要保存根节点,在左右子树都访问后再访问根节点。如果左右子树为空或者已访问就可以访问根节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| while(!empty_s()) {
cur=gettop(); if((cur->lchild==NULL&&cur->rchild==NULL)||/ (pre!=NULL&&(pre==cur->lchild||pre==cur->rchild))) { printf("%c ",cur->data); pop_s(); pre=cur; } else { if(cur->rchild!=NULL) push_s(cur->rchild); if(cur->lchild!=NULL) push_s(cur->lchild); } }
|
广度遍历
利用队列,当队列退出根节点时访问根节点,然后左右子树进入队列。
1 2 3 4 5 6 7 8 9 10
| while(!empty_q()) { p=getfront(); printf("%c ",p->data); deque(); if(p->lchild!=NULL) enque(p->lchild); if(p->rchild!=NULL) enque(p->rchild); }
|
图
图的定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| typedef struct adjacencyArc //定义图的边 { int adjNode;//边连接的下个点 int weight;//权重 struct adjacencyArc *next;//连接下一条边 }arc,*Arc;
typedef struct adjacencyNode//邻接点 { char nodeName;//节点名称 struct adjacencyArc* firstArc;//节点第一条边 }vertex,*AdjList;
typedef struct Graph { AdjList adjList; int vertexNum; int edgeNum; }graph; //每个点
|
prime算法(从一个点开始,每次找出已加入的点集合集合的最小的边,再根据边连接的点加入集合,
直到所有点加入集合)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| void prime(graph *g,int sv) { int count=0; int *array=malloc((g->vertexNum+1)*sizeof(int)); arc **array_p=malloc((g->vertexNum+1)*sizeof(Arc)); //array_p[0]-array_p[n] 分配空间 if(array==NULL||array_p==NULL) { printf("not enough mermory!\n"); exit(0); } int min,i,n=0; for(i=0;i<g->vertexNum;i++) { array_p[i]=NULL;//初始化存储边的指针 } array[count++]=sv; while (count<g->vertexNum) { min=MAX; arc *p,*q; for(i=0;i<count;i++)//找出已有点集合中的最小边 { p=g->adjList[array[i]].firstArc; while (p!=NULL) { if(find_p(array_p,p,g->vertexNum)) { p=p->next; } else { if(p->weight<min) { min=p->weight; q=p; } p=p->next; } } } array[count++]=q->adjNode; array_p[n++]=q; }//while for(i=0;i<g->vertexNum;++i) { arc *t=g->adjList[array[i]].firstArc; printf("%c->",g->adjList[array[i]].nodeName); while (t!=NULL) { if(find_p(array_p,t,g->vertexNum)) printf("%c->",g->adjList[t->adjNode].nodeName); t=t->next; } printf("NULL\n"); }
}
|
Kruskal算法(每次找出所有边中最小的边,根据边把点加入集合,知道所有点加入集合)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| void Kruskal(graph *g) { int i=0,j,vt,n=0,k=0; int *array=malloc(g->vertexNum*sizeof(int));//存储点 arc **array_arc=malloc((g->vertexNum-1)*sizeof(Arc)); arc *min; for(j=0;j<g->vertexNum-1;j++) { min=NULL; for(i=0;i<g->vertexNum;i++) { arc *p=g->adjList[i].firstArc; while (p!=NULL) { if(!find_p(array_arc,p,g->vertexNum-1)) { if(min==NULL) { vt=i; min=p; } else if(min!=NULL&&(min->weight>p->weight)) { vt=i; min=p; } } p=p->next; }
}//找到最小的边
if(!find_v(array,vt,g->vertexNum)) { array[k++]=vt; } if(!find_v(array,min->adjNode,g->vertexNum)) { array[k++]=min->adjNode; }//加入点还需加入边 array_arc[n++]=min; } for(i=0;i<g->vertexNum;++i) { arc *t=g->adjList[array[i]].firstArc; printf("%c->",g->adjList[array[i]].nodeName); while (t!=NULL) { if(find_p(array_arc,t,g->vertexNum-1)) printf("%c->",g->adjList[t->adjNode].nodeName); t=t->next; } printf("NULL\n"); }//比较合适的方法就是新建一个生成树。或者在判断节点的时候同时判断weight. free(array); free(array_arc); array=NULL; array_arc=NULL; }
|
github地址