Vanish

数据结构


数据结构

树,图


二叉树遍历

非递归前序遍历

利用栈来实现遍历,在每次将节点压入栈时访问也就是只要到当前节点就访问。
然后访问左子树,然后右子树。
代码如下:

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地址