线性表
线性表定义
零个或多个数据元素的有限序列
线性表有序序列,数据元素具有相同的特性,线性表可以有无性
线性表特点
1.有序性
数据元素之间是(一对一)的关系
2.有限性
线性表的元素个数是有限的
ps 零个数据元素线性表叫空表
线性表存储结构
有顺序结构和链式存储结构
前者是 顺序表,后者是链表。
1.顺序表
这里看看就好了,主要还是链表部分吧。。。。(因为大部分我都是直接上模板的,没怎么看过,应该不难吧,如果有bug,欢迎来打脸=_=||)
定义数据元素和顺序表
const int MAX_SIZE=100;
//定义数据元素
//自定义一个新数据类型
//其实就是int,double等等的合集
typedef struct{
int id1;
char *name;
}element_type;
//定义顺序表结构
typedef struct{
element_type datas[MAX_SIZE];//顺序表中的数据元素集合
int length;//当前顺序表中的元素个数
}seqlist;
初始化顺序表以及插入操作
先说插入操作,因为你要初始化顺序表,其实就是把数据元素一个一个按顺序插入到顺序表中
//参数介绍
//seqlist 顺序表
//index 要插入的下标
//element_type 要插入的元素
void insertelement (seqlist * seqlist1,int index ,element_type element)
{
if(seqlist1->length + 1 >= MAX_SIZE)
{
printf("数组已满,无法插入\n");
return ;
}
if(index < 0 || index > MAX_SIZE - 1)
{
printf("插入下标错误,无法插入\n");
return ;
}
if(index > seqlist1 -> length)
{
printf("插入的下标超过数组长度-1,无法插入\n");
return ;
}
//下面正式插入模板
for(int i = seqlist1 -> length-1;i >= index ;i--)
{
seqlist1->datas[i+1] = seqlist1 -> datas[i];
}
seqlist1 -> datas[index] = element;
//注意总长度加一
seqlist1 -> length++;
}
然后是初始化就很简单了,唯一的注意点就是要初始化长度为0,很重要!
//参数介绍
//seqlist 要初始化的顺序表
//element_type 初始化时要添加的元素内容数组
//length 初始化时要添加的元素个数
void initlist(seqlist * seqlist1,element_type * elemarray ,int length)
{
if(length > MAX_SIZE)
{
printf("超出最大容量,无法初始化\n");
return ;
}
seqlist -> length =0;//注意点
for(int i=0;i<length;i++)
{
insertelement(seqlist1 , i ,elemarray[i]);
}
}
删除操作和寻找操作
element_type * getelement (seqlist * seqlist1 ,int index)
{
if(index < 0 || index > MAX_SIZE - 1)
{
printf("下标越界,无法寻找\n");
return NULL;
}
element_type * element;
element = &seqlist1->datas[index];
}
element_type * delete_element(seqlist * seqlist1,int index);
{
if(index < 0 || index > MAX_SIZE - 1)
{
printf("下标越界,无法删除\n");
return NULL;
}
//找到要删除元素
element_type * delelement =(element_type*)malloc(sizeof(element_type));
delelment = getelement(seqlist1 ,index);
for(int i= index; i < seqlist1->length-1;i++)
{
seqlist1->datas[i] = seqlist1 -> datas[i+1];
}
seqlist1->length--;
return delelement ;//记得free
}
其他小操作
int getlenth(seqlist * seqlist1)
{
if(seqlist1==NULL)
return 0;
return seqlist1->length;
}//找到顺序表长度
bool isempty(seqlist * seqlist1)
{
return getlenth(seqlist1)==0;
}//判断是否为空
void clearlist(seqlist * seqlist1)
{
if(seqlist1 ==NULL) return ;
seqlist1 -> length = 0;
}//清除线性表
2.单链表
这里说下可能会恶心的点
1.原本我们短学期之前做的head里面是有数据的,而下面的代码中,head的数据域中是空的,也就是我们只用它的指针部分(因为这个,我按照以前的思维一直删除,插入的时候位置总是差一个,也不知道问题)
2.下面有一个参数是(node ** l)
这个就是(指针l的地址,应该理解理解就行不难,主要还是第一个问题)
定义链表
typedef struct{
int id1;
char *name;
}element_type;
//在复习一遍自定义,当然像下面一样不用也行
typedef struct node{
//int id1;
//char * name;
element_type data;
struct node * next;//指向下个结点
}node;
创建操作
void create(node ** l,int n,element_type dataarray[])
{
node *p1, *p2;
int i;
*l = (node*) malloc (sizeof(node));
p2 = *l;
for(i=0 ;i<n;i++)
{
p1=(node*) malloc (sizeof(node));
p1->data = dataarray[i];
p2->next = p1;
//p1->next=NULL;
p2=p1;
}
p2->next = NULL;
}
插入
void insertlinklist(node ** l,int i,element_type e)
{
int j=1;
node *p,*p1;
p = *l;
while(p && j<i)//p就是 p!=NULL
{
p = p->next;
j++;
}
if(!p || j>i)
{
//printf("错误\n");
return ;
}
p1 = (node *)malloc(sizeof(node));
p1->data = e;
p1->next = p->next;
p->next = p1;
}
删除
void deletelinklist(node ** l,int i,element_type *e)
{
int j=1;
node *p,*p1;
p = *l;
while(p->next && j<i)
{
p = p->next;
j++;
}
if(!(p->next)||j>i)
{
return ;
}
p1 = p->next;
p->next =p1->next;
*e = p1->data; //这就是删除的元素
free(p1);
}
//整体删除
void clearlist(node ** l)
{
node* p,*p1;
p = (*l)->next;
while(p)
{
p1 = p->next;
free(p);
p = p1;
}
(*l)->next = NULL;
}
查询
void getelem(node **l,int i,element_type *e)//查询
{
int j=1;
node * p;
p = (*l)->next;
j=1;
while(p && j<i)
{
p=p->next;
j++;
}
if(!p || j>i)
{
//printf("错误\n");
return ;
}
*e = p->data;
return ;
}
输出
void print(node ** l)// 输出
{
node*temp=(*l)->next;
while(temp!=NULL)
{
printf("%d\t%s\n",temp->data.id1,temp->data.name);
temp = temp->next;
}
}
小小总结一下(水文章)
如果线性表要频繁查找,很少插入和删除,那么顺序表更佳,否则就用链表;
如果元素的个数变化较大或不清楚时,用链表更好;
3.双向链表
双向链表支持两个方向,每个节点有一个后继指针next指向后面的节点,还有一个前驱指针指向前面的节点。
typedef struct {
int id1;
//char* name;
}element_type;
typedef struct node {
element_type data;
struct node* prior;
struct node* next;
}node;
void init(node** l,int n, element_type dataarray[])
{
node* p, * q;
int i;
*l = (node*)malloc(sizeof(node));
if (!(*l))
return;
(*l)->next = (*l)->prior = NULL;
p = (*l);
for (i = 0; i < n; i++)
{
q = (node*)malloc(sizeof(node));
if (!q)
return;
q->data = dataarray[i];
q->prior = p;
p->next = q;
p = q;
}
p->next = NULL;
//双向循环
//p->next =(*l)->next;
//(*l)->next->prior = p;
}
void insert(node** l, int i, element_type e)
{
int j = 1;
node* p, * s;
p = *l;
while (p && j < i)//p就是 p!=NULL
{
p = p->next;
j++;
}
if (!p || j > i)
{
return;
}
s = (node*)malloc(sizeof(node));
s->data = e;
s->prior = p;
if (!p->next)
{
s->next = NULL;
}
else
{
p->next->prior = s;
s->next = p->next;
}
p->next = s;
}
void delete1(node** l, int i)
{
int j = 1;
node* p;
p = (*l)->next;
while (p && j < i)
{
p = p->next;
j++;
}
if (!(p) || j > i)
{
return;
}
if (p->next == NULL)
{
p->prior->next = p->next;
}
else
{
p->prior->next = p->next;
p->next->prior = p->prior;
}
free(p);
}
4.循环链表
对于单链表而言,最后一个结点指针域是空指针,如果将该链表头指针置入该指针域,则使得链表头尾结点相连,这就构成了单循环链表。和单链表的操作基本相同,只是把最后一个结点的指针域指向头指针而已,其他没有变化。
栈
定义:
栈(stack) 是一个后进先出的线性表(LIFO),他要求只在表尾进行删除和插入操作
插入(push),即进栈
删除(pop),即出栈
栈顶(top)
栈底(bottom)
顺序结构
typedef struct {
int id1;
//char* name;
}element_type;
typedef struct
{
element_type* base;//栈底的指针变量
element_type* top;//栈顶的指针变量
int stacksize;//当前可用最大容量
}stack;
void initstack(stack* s)//创建
{
s->base = (element_type*)malloc(100 * sizeof(element_type));
if (!s->base)
exit(0);//申请失败
s->top = s->base;//开始栈底就是栈顶
s->stacksize = 100;//这里可以用变量,上面也要改
}
void push(stack* s, element_type e)
{
if (s->top - s->base >= s->stacksize)//如果栈大小不够要增加容量
{
s->base = (element_type*)realloc(s->base, (s->stacksize + 10));//10可以变量代替更好
if (!s->base)
exit(0);
s->top = s->base + s->stacksize;
s->stacksize = s->stacksize + 10;//10变量代替
}
*(s->top) = e;
s->top++;
}
void pop(stack *s,element_type *e)
{
if (s->top == s->base)//栈空
return;
*e = *--(s->top);//--i和i--可以复习一下
}
//其他小操作
void clear(stack* s)
{
s->top = s->base;//这里申请的空间没有释放
}
void destroy(stack* s)//相当于要重新创建了
{
int i, len;
len = s->stacksize;
for (i = 0; i < len; i++)
{
free(s->base);
s->base++;
}
s->base = s->top = NULL;
s->stacksize = 0;
}
int len(stack s)//当前容量
{
return(s.top - s.base);//指针之间可以相减不能相加
}
链式结构
(好像不用学=。=,只是一个知识点)
了解了解
typedef struct {
int id1;
//char* name;
}element_type;
typedef struct stack
{
element_type data;
struct stack* next;
}stack;
typedef struct linkstack
{
stack* top;
int count;//计数器
};
void push(linkstack* s, element_type e)
{
stack* p = (stack*)malloc(sizeof(stack));
p->data = e;
p->next = s->top;
s->top = p;
s->count++;
}
void pop(linkstack *s,element_type *e)
{
stack* p;
if (s->count==0)
return;//是否为空
*e = s->top->data;
p = s->top;
s->top = s->top->next;
free(p);
s->count--;
}
队列
定义:
队列(queue)是只允许在一端进行插入,在另一端进行删除操作的线性表,和栈不同的是,队列先进先出(FIFO);
顺序队列
参考循环队列
#define MAXSIZE 100
typedef struct {
int id1;
//char* name;
}element_type;
typedef struct node {
element_type* base;//用数组也行
int front, rear;
}node;
void init(node* q)
{
q->base = (element_type*)malloc(sizeof(element_type) * MAXSIZE);
if (!q->base)
exit(0);
q->front = q->rear = 0;
}
void push(node* q,element_type e)
{
if ((q->rear + 1) % MAXSIZE == q->front)
{
return;//队列已满
}
q->base[q->rear] = e;
q->rear = (q->rear + 1) % MAXSIZE;
}
void pop(node* q)
{
if (q->front == q->rear)
return;//队列为空
q->front = (q->front + 1) % MAXSIZE;
}
链式队列
typedef struct {
int id1;
//char* name;
}element_type;
typedef struct node {
element_type data;
struct node* next;
}node;
typedef struct {
node* front,* rear;//队列头和尾指针
}linkqueue;
void initqueue(linkqueue* q)
{
q->front = q->rear = (node*)malloc(sizeof(node));
if (!q->front)
exit(0);
q->front->next = NULL;
}
void push(linkqueue* q, element_type e)
{
node* p;
p = (node*)malloc(sizeof(node));
if (p == NULL)
exit(0);
p->data = e;
p->next = NULL;
q->rear->next = p;
q->rear = p;
}
void pop(linkqueue* q, element_type* e)
{
node* p;
if (q->front == q->rear)
return;
p = q->front->next;
*e = p->data;
q->front->next = p->next;
if (q->rear == p)
q->rear = q->front;
free(p);
}
void dextroy(linkqueue* q)
{
while (q->front)
{
q->rear = q->front->next;
free(q->front);
q->front = q->rear;
}
}
树
定义
树(tree)是n(>=0)个结点的有限集。当n=0是为空树。
在任意一棵非空树中:
1.有且只有一个称为根(root)的结点。
2.当n>1时,其余结点可分为m(m>0)个互不相交的有限集,每一个集合本身也是一棵树,称为根的子树。
结点拥有的子树数称为结点的度,树的度取树内的各结点的度的最大值。
1.度为0的结点称为叶结点(leaf)或终端结点
2.度不为0的结点称为分支结点或非终端结点,除根结点外,分支结点也称为内部结点
树中结点的最大层次称为树的深度(depth)或高度
定义代码
#define MAXSIZE 100
typedef struct {
int id1;
//char* name;
}element_type;
//孩子结点
typedef struct node {
int child;//孩子结点的下标
struct node* next;//指向下一个孩子
}node;
//表头结构
typedef struct
{
element_type data;
int parent;//标记父亲的位置
node** child;//指向孩子的指针
}tree;
typedef struct
{
tree nodes[MAXSIZE];//结点数组
int r, n;//根的位置和结点数
}tree;
二叉树
二叉树(binary tree)每个结点最多(不是一定)有两个子树,所以二叉树中不存在度大于2的结点。
基本形态
1.空二叉树
2.只有一个根结点
3.根结点只有左子树
4.根结点只有右子树
5.根结点既有左子树也有右子树
特殊二叉树
斜树
每个结点只有左儿子(左斜树)或者右儿子(右斜树)
满二叉树
所有的分支节点都有左子树和右子树,并且所有叶子在同一层上,这样的二叉树称为满二叉树。
1.叶子只能出现在最下一层
2.非叶子结点的度一定是2
3.在同样深度的二叉树中,满二叉树的结点个数一定是最多,同时叶子也是最多
完全二叉树
设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
1.叶子结点只能出现在最下两层
2.最下层的叶子一定集中在左部连续位置
3.倒数第二层若有叶子结点,一定都在右边连续位置
4.如果结点的度为1,那么该结点只有左儿子
5.同样结点树的二叉树,完全二叉树的深度最小
ps:完全二叉树不一定是满二叉树,满二叉树一定是完全二叉树
性质
1.在二叉树的第i层上至多有2i+1个结点(i>=1)
2.深度为k的二叉树至多有2k-1个结点(k>=1)
3.对任意一棵二叉树,如果其终端结点树为
n
0
n_0
n0,度为2
的结点树为
n
2
n_2
n2,则
n
0
=
n
2
+
1
n_0=n_2+1
n0=n2+1
4.具有n个结点的完全二叉树的深度为
⌊
log
2
n
⌋
\left \lfloor \log_2n \right \rfloor
⌊log2n⌋+1(向下取整)
5.如果对一个有n个结点的完全二叉树(深度
⌊
log
2
n
⌋
\left \lfloor \log_2n \right \rfloor
⌊log2n⌋+1)的结点按层序编号,对任意结点i(1<=i<=n)有以下性质;
(1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则双亲的结点是
⌊
i
2
⌋
\left \lfloor \frac i2 \right \rfloor
⌊2i⌋
(2)如果2i>n,则结点i无左儿子(结点i就是叶子结点);否则左儿子为结点2i
(3)如果2i+1>n,则结点i无右儿子;否则右孩子是结点2i+1
可实行代码
定义
typedef struct {
int id1;
char* name;
}element_type;
typedef struct node
{
element_type data;
struct node* left, * right;
}node;
//创建
void init(node** t)
{
element_type e;
scanf("%d%s", &e.id1,e.name);
if(条件)//递归结束条件
*t = NULL;
else
{
*t = (node*)malloc(sizeof(node));
(*t)->data = e;
init(&(*t)->left);
init(&(*t)->right);
}
//当然用数组也可以,这个好像输入的时候麻烦
}
遍历
从根结点出发,按某种次序依次访问二叉树中的所有结点,每个结点被访问一次且仅被访问一次
1.前序遍历,若二叉树为空;则空操作返回;
否则先访问根结点,然后前序遍历左子树,在前序遍历右子树
2.中序遍历,若二叉树为空;则空操作返回;
否则遍历最左的左子树,然后访问根结点,最后遍历右子树
3.后序遍历,若二叉树为空;则空操作返回;
否则从左到右先叶子后结点的方式遍历访问左右子树,最后访问根结点
4.层序遍历,若二叉树为空;则空操作返回;
否则从根结点,从上到下逐层访问,同一层从左往右遍历
其实就是算法中的bfs要用到队列
void visit(element_type e)
{
printf("id:%d\tname:%s\n", e.id1,e.name);
}
void search1(node* t)//前序遍历
{
if (t)//不为空就可以访问
{
visit(t->data);
search1(t->left);
search1(t->right);
}
}
void search2(node* t)//中序遍历
{
if (t)//不为空就可以访问
{
search2(t->left);
visit(t->data);
search2(t->right);
}
}
void search3(node* t)//后序遍历
{
if (t)//不为空就可以访问
{
search3(t->left);
search3(t->right);
visit(t->data);
}
}
线索二叉树
充分利用二叉链表中的空链域,将遍历过程中结点的前驱、后继信息保存下来。
1.若结点有左子树,则其 LChild 域指向其 左孩子,否则 LChild 域指向其 前驱结点。
2.若结点有右子树,则其 RChild 域指向其 右孩子,否则 RChild 域指向其 后继结点。
typedef struct node
{
element_type data;
struct node* left, * right;
//区别线索化,true=1表示前驱后继,false=0表示左右孩子指针;
bool ltag, rtag;
}node;
void InThread(node* p, node*& pre)//建立中序线索二叉树
{
if (p != NULL)
{
InThread(p->left, pre); // 递归,左子树线索化
if (p->left == NULL) // 建立当前结点的前驱线索
{
p->left = pre;
p->ltag = true;
}
if (pre != NULL && pre->right == NULL) //建立前驱结点的后继线索
{
pre->right = p;
pre->rtag = true;
}
pre = p;
InThread(p->right, pre); // 递归,右子树线索化
}
}
void createInThread(node* root)
{
node* pre = NULL; // 前驱结点指针
if (root != NULL)
{
InThread(root, pre);
pre->right = NULL; // 处理最后一个结点的后继
pre->rtag = true;
}
}
//中序遍历
node* First(node* p) // 找到最左下的结点
{
while (p->ltag == 0)
p = p->left;
return p;
}
node* Next(node* p)
{
if (p->rtag == 0) // 如果p存在右孩子,则p的后继结点是p的右子树中的最左下结点
return First(p->right);
return p->right;
}
void Inorder(node* root)
{
for (node* p = First(root); p != NULL; p = Next(p))
visit(p->data);
}
转换
树转换到二叉树
1.将每一个结点与他的兄弟结点之间连一条线。
2.对每一个双亲结点,只保留它与第一个子结点的连线,删除与其余结点的连线。
3.整理,左右摆齐。
森林转换到二叉树
1.把每棵树按照上面的方式转换为二叉树。
2.第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子,用线连接起来。
二叉树转换到树
1.加线。若某结点X的左孩子结点存在,则将这个左孩子的右孩子结点、右孩子的右孩子结点、右孩子的右孩子的右孩子结点…,都作为结点X的孩子。将结点X与这些右孩子结点用线连接起来。
2.去线。删除原二叉树中所有结点与其右孩子结点的连线。
3.层次调整。
二叉树转换为森林
备注:假如一棵二叉树的根节点有右孩子,则这棵二叉树能够转换为森林,否则将转换为一棵树。
1.从根节点开始,若右孩子存在,则把与右孩子结点的连线删除。再查看分离后的二叉树,若其根节点的右孩子存在,则连线删除…。直到所有这些根节点与右孩子的连线都删除为止。
2.将每棵分离后的二叉树转换为树。
图
定义:
图(graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中的顶点的集合,E是图G中边的集合。
注意点:
1.线性表可以没有元素,称为空表,树中没有结点,叫做空树,而图结构强调顶点集合V要有穷非空。
2.线性表中,相邻的数据元素之间有线性关系,数据结构中,相邻两层的结点具有层次关系,而图结构中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。
无向边:若顶点 v i v_i vi到 v j v_j vj之间的边没有方向,则称这条边为无向边(edge),用无序偶( v i , v j v_i,v_j vi,vj)来表示。
有向边:若顶点 v i v_i vi到 v j v_j vj之间的边有方向,则称这条边为有向边,也称为弧(arc),用无序偶< v i , v j v_i,v_j vi,vj>来表示, v i v_i vi称为弧尾, v j v_j vj称为弧头。
简单图:在图结构中,若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。
无向完全图:在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。含有n个顶点的无向完全图有n*(n-1)/2条边。
有向完全图:在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧,则称该图为有向完全图。含有n个顶点的无向完全图有n*(n-1)条边。
稀疏图和稠密图:这里的稀疏和稠密是模糊的概念,都是相对而言的,通常认为边或弧数小于n* log n \log n logn(n是顶点的个数)的图称为稀疏图,反之称为稠密图。
有些图的边或者弧带有与它相关的数字,这种与图的边或弧相关的数叫做权(weight),带权的图通常被称为网(networt)。
假设有两个图G1=(V1,E1)和G2=(V2,E2),如果V2 ⊆ \subseteq ⊆V1,E2 ⊆ \subseteq ⊆E1,则称G2为G1的子图(subgraph)
图的顶点和边之间的关系:
1.对于无向图G=(V,E),如果边(V1,V2)
⊆
\subseteq
⊆ E,则称顶点V1和V2互为邻接点(adjacent),即V1和V2相邻接。边(V1,V2)依附(incident)于顶点V1和V2,或者说边(V1,V2)与顶点V1和V2相关联。
顶点V的度(degree)是和V相关联的边的数目,记为TD(V)。
2.对于有向图G=(V,E),如果边<V1,V2>
⊆
\subseteq
⊆ E,则称顶点V1邻接到顶点V2,顶点V2邻接自顶点V1。
以顶点V为头的弧的数目称为V的入度(indegree),记为ID(V);以顶点V为尾的弧的数目称为V的出度(outdegree),记为OD(V),因此顶点V的度为TD(V)=ID(V)+ OD(V)。
无向图G=(V,E)中从顶点V1到顶点V2的路径(path)
路径的长度是路径上的边或弧的数目。
第一个顶点到最后一个顶点相同的路径称为回路或环(cycle)
序列中顶点不重复出现的路径称为简单路径,除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路,称为简单回路或简单环
在无向图G中,如果从顶点V1到顶点V2有路径,则称V1和V2是连通的,如果对于图中任意两个顶点
V
i
,
V
j
V_i,V_j
Vi,Vj是连通的,则称G是连通图(connectedgraph)
在有向图G中,如果对于每一对顶点
V
i
,
V
j
V_i,V_j
Vi,Vj都存在路径,则称G是强连通图
有向图中的极大强连通子图称为有向图的强连通分量
图的生成树:一个连通图的生成树是一个极小的连通子图,它含有图中全部的n个顶点,但只有足以构成一棵数的n-1条边。
如果一个有向图恰有一个顶点入度为0,其余顶点的入度为1,则是一棵有向树。
代码
1.邻接矩阵(adjacency matrix)
用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息。
#define Maxvex 100
#define Infinity 65535
typedef struct
{
char vexs[Maxvex]; //顶点表
int arc[Maxvex][Maxvex]; //邻接矩阵,可看作边表
int numVertexes, numEdges; //图中当前的顶点数和边数
}MGraph;
//有了上面的结构定义,构造一个图,其实就是给顶点表和边表输入数据的过程。
//建立无向网图的邻接矩阵表示
void CreateMGraph(MGraph* G)
{
int i, j, k, w;
printf("请输入顶点数和边数:\n");
scanf("%d,%d", &G->numVertexes, &G->numEdges);
for (i = 0; i < G->numVertexes; i++)
{
scanf(&G->vexs[i]);
}
for (i = 0; i < G->numVertexes; i++)
for (j = 0; j < G->numVertexes; i++)
G->arc[i][j] = Infinity; //邻接矩阵初始化
for (k = 0; k < G->numEdges; k++)
{
printf("输入边(vi,vj)的下标i,下标j和权w:\n");
scanf("%d,%d,%d", &i, &j, &w);
G->arc[i][j] = w;
G->arc[j][i] = G->arc[i][j];
}
}
2.邻接图
//结点的定义
#define MaxVex 100
typedef struct EdgeNode //边表结点
{
int adjvex; //邻接点域,存储邻接顶点对应的下标
int weight; //用于存储权值,对于非网图可以不需要
struct EdgeNode *next; //链域,指向下一个邻接点
}EdgeNode;
typedef struct VertexNode //顶点表结点
{
char data; //顶点域,存储顶点信息
EdgeNode *firstedge; //边表头指针
}VertexNode,AdjList[MaxVex];
typedef struct
{
AdjList adjList;
int numVertexes,numEdges; //图中当前顶点数和边数
}GraphAdjList;
//建立无向图的邻接表结构
void CreateALGraph(GraphAdjList *G)
{
int i,j,k;
EdgeNode *e;
printf("输入顶点数和边数:\n");
scanf("%d,%d",&G->numVertexes,&G->numEdges);
for(i=0;i<G->numVertexes;i++)
{
scanf(&G->adjList[i].data); //输入顶点信息
G->adjList[i].firstedge = NULL; //将边表置为空表
}
for(k=0;k<G->numEdges;k++)
{
printf("输入边(vi,vj)上的顶点序号:\n");
scanf("%d,%d",&i,&j);
e = (EdgeNode *)malloc(sizeof(EdgeNode)); //向内存申请空间,生成边表结点
e->adjvex = j; //邻接序号为j
e->next = G->adjList[i].firstedge;
G->adjList[i].firstedge = e; //将当前顶点的指针指向e
e = (EdgeNode *)malloc(sizeof(EdgeNode));
e->adjvex = i; //邻接序号为i
e->next = G->adjList[j].firstedge;
G->adjList[j].firstedge = e;
}
}