一.图及相关操作
1.老师的代码(重点关注图相关代码)
结构体
typedef struct Graph{
int** connections;
int numNodes;
}*GraphPtr;
初始化
GraphPtr initGraph(int paraSize,int** paraData){
int i,j;
GraphPtr resultPtr=(GraphPtr)malloc(sizeof(struct Graph));
resultPtr->numNodes=paraSize;
resultPtr->connections=(int**)malloc(paraSize*sizeof(int*));
for (i=0;i<paraSize;i++){
resultPtr->connections[i]=(int*)malloc(paraSize*sizeof(int));
for (j=0;j<paraSize;j++){
resultPtr->connections[i][j]=paraData[i][j];
}
}
return resultPtr;
}
初始化记录数组及深度优先遍历
void initTranverse(GraphPtr paraGraphPtr){
int i;
visitedPtr=(int*)malloc(paraGraphPtr->numNodes*sizeof(int));
for (i=0;i<paraGraphPtr->numNodes;i++){
visitedPtr[i]=0;
}
}
void depthFirstTranverse(GraphPtr paraGraphPtr,int paraNode) {
int i;
visitedPtr[paraNode] = 1;
printf("%d\t",paraNode);
for (i=0;i<paraGraphPtr->numNodes;i++){
if (!visitedPtr[i]){
if (paraGraphPtr->connections[paraNode][i]){
depthFirstTranverse(paraGraphPtr,i);
}
}
}
}
广度优先遍历
void widthFirstTranverse(GraphPtr paraGraphPtr,int paraStart){
int i,j,tempNode;
i=0;
QueuePtr tempQueuePtr=initQueue();
printf("%d\t",paraStart);
visitedPtr[paraStart]=1;
enqueue(tempQueuePtr,paraStart);
while(!isQueueEmpty(tempQueuePtr)){
tempNode=dequeue(tempQueuePtr);
visitedPtr[tempNode]=1;
i++;
for (j=0;j<paraGraphPtr->numNodes;j++){
if (visitedPtr[j])
continue;
if (paraGraphPtr->connections[tempNode][j]==0)
continue;
printf("%d\t",j);
visitedPtr[j]=1;
enqueue(tempQueuePtr,j);
}
}
}
运行结果
Preparing data
Data ready
num nodes = 5
Graph initialized
Depth first visit:
4 1 0 3 2
Width first visit:
4 1 2 0 3 Press any key to continue
2.自己的代码
#include <stdio.h>
#include <malloc.h>
#include <stdbool.h>
#define QUEUE_SIZE 10
int* visited;
typedef struct GraphNQ{
int* nodes;
int front;
int rear;
}*Queueptr;
Queueptr initQueue()
{
Queueptr result=(Queueptr)malloc(sizeof(struct GraphNQ));
result->nodes=(int*)malloc(QUEUE_SIZE*sizeof(int));
result->front=0;
result->rear=1;
return result;
}
bool cheak(Queueptr p)
{
if ((p->front+1)%QUEUE_SIZE==p->rear)
return true;
return false;
}
void enqueue(Queueptr p,int paraN)
{
if ((p->rear+1)%QUEUE_SIZE==p->front%QUEUE_SIZE){
printf("Error Queue full\r\n");
return;
}
p->nodes[p->rear]=paraN;
p->rear=(p->rear+1)%QUEUE_SIZE;
}
int dequeue(Queueptr p)
{
if (cheak(p)){
printf("Error empty\r\n");
return -1;
}
p->front=(p->front+1)%QUEUE_SIZE;
return p->nodes[p->front];
}
typedef struct Graph{
int** connections;
int num;
}*GraphPtr;
GraphPtr initGraph(int paraS,int** paraD)
{
GraphPtr resultPtr=(GraphPtr)malloc(sizeof(struct Graph));
resultPtr->num=paraS;
resultPtr->connections=(int**)malloc(paraS*sizeof(int*));
for (int i=0;i<paraS;i++){
resultPtr->connections[i]=(int*)malloc(paraS*sizeof(int));
for (int j=0;j<paraS;j++)
resultPtr->connections[i][j]=paraD[i][j];
}
return resultPtr;
}
void initT(GraphPtr paraGraph)
{
visited=(int*)malloc(paraGraph->num*sizeof(int));
for (int i=0;i<paraGraph->num;i++)
visited[i]=0;
}
void depth(GraphPtr pGraph,int paraN)
{
visited[paraN] = 1;
printf("%d\t",paraN);
for (int i=0;i<pGraph->num;i++){
if (!visited[i]){
if (pGraph->connections[paraN][i])
depth(pGraph,i);
}
}
}
void width(GraphPtr pGraph,int pStart)
{
int tNode;
Queueptr tQueue=initQueue();
printf("%d\t",pStart);
visited[pStart]=1;
enqueue(tQueue,pStart);
int i=0;
while(!cheak(tQueue)){
tNode=dequeue(tQueue);
visited[tNode]=1;
i++;
for (int j=0;j<pGraph->num;j++){
if (visited[j])
continue;
if (pGraph->connections[tNode][j]==0)
continue;
printf("%d\t",j);
visited[j]=1;
enqueue(tQueue,j);
}
}
}
void test()
{
int graph[5][5]={
{0,1,1,1,0},
{1,0,1,0,1},
{1,1,0,1,1},
{1,0,1,0,0},
{0,1,1,0,0}
};
int** tempPtr;
tempPtr=(int**)malloc(5*sizeof(int*));
for (int i=0;i<5;i++) {
tempPtr[i]=(int*)malloc(5*sizeof(int));
}
for (int i=0;i<5;i++) {
for (int j=0;j<5;j++)
tempPtr[i][j]=graph[i][j];
}
GraphPtr tempGraphPtr=initGraph(5,tempPtr);
printf("num nodes = %d \r\n",tempGraphPtr->num);
printf("Depth:\r\n");
initT(tempGraphPtr);
depth(tempGraphPtr,4);
printf("\r\nWidth:\r\n");
initT(tempGraphPtr);
width(tempGraphPtr,4);
}
void main(){
test();
}
运行结果
1.图是由顶点集合以及顶点间的关系集合组成的一种数据结构。
2.图是按照无方向和有方向分为无向图和有向图。图的遍历方式分为两种:深度优先遍历与广度优先遍历,二者的时间复杂度都是O(n2).
二.邻接表及相关操作
老师的代码(重点理解邻接表相关)
结构体
typedef struct AdjacencyNode {
int column;
struct AdjacencyNode* next;
}AdjacencyNode, *AdjacentNodePtr;
typedef struct AdjacencyList {
int num;
struct AdjacencyNode* headers;
}AdjacencyList, *AdjacencyListPtr;
创建邻接表
AdjacencyListPtr graphToAdjacentList(GraphPtr paraPtr){
int i,j,tempNum;
AdjacentNodePtr p,q;
tempNum=paraPtr->num;
AdjacencyListPtr resultPtr=(AdjacencyListPtr)malloc(sizeof(struct AdjacencyList));
resultPtr->num=tempNum;
resultPtr->headers=(AdjacencyNode*)malloc(sizeof(struct AdjacencyNode)*tempNum);
for(i=0;i<tempNum;i++){
p=&(resultPtr->headers[i]);
p->column=-1;
p->next=NULL;
for(j=0;j<tempNum;j++){
if(paraPtr->connections[i][j]>0){
q=(AdjacentNodePtr)malloc(sizeof(struct AdjacencyNode));
q->column=j;
q->next=NULL;
p->next=q;
p=q;
}
}
}
return resultPtr;
}
打印邻接表
void printAdjacentList(AdjacencyListPtr paraPtr){
int i;
AdjacentNodePtr p;
int tempNum=paraPtr->num;
printf("This is the graph:\r\n");
for (i=0;i<tempNum;i ++){
p=paraPtr->headers[i].next;
while (p!=NULL){
printf("%d, ",p->column);
p=p->next;
}
printf("\r\n");
}
}
遍历
void width(AdjacencyListPtr paraListPtr,int pStart){
printf("width first \r\n");
int i,j,tNode;
AdjacentNodePtr p;
i=0;
visited=(int*)malloc(paraListPtr->num*sizeof(int));
for(i=0;i<paraListPtr->num;i++){
visited[i]=0;
}
QuenePtr tQueue=initQuene();
printf("%d\t",pStart);
visited[pStart]=1;
enquene(tQueue,pStart);
while (!cheak(tQueue)){
tNode=dequene(tQueue);
for(p=&(paraListPtr->headers[tNode]);p!=NULL;p=p->next){
j=p->column;
if(visited[j])
continue;
printf("%d\t",j);
visited[j]=1;
enquene(tQueue,j);
}
}
printf("\r\n");
}
运行结果
图的邻接表存储方法跟树的链式表示法相类似。
这是一种顺序和链式相结合的存储结构。如头结点所对应的顶点存在相邻顶点,则把相邻顶点依次存放于头结点所指向的单向链表中。表结点存放的是邻接顶点在数组中的索引。对于无向图来说,使用邻接表进行存储也会出现数据冗余。表头结点A所指链表中存在一个指向C的表结点的同时,表头结点C所指链表也会存在一个指向A的表结点。