这是一篇记录《数据结构》课程课后作业的博客,我所使用的教科书是严蔚敏主编的C语言版数据结构,但是由于习惯所致,本篇博客会尽量在和书本风格同步的情况下使用C++编写程序,本文中的程序都是李岚老师上课布置的题目的个人解析,如有漏洞,欢迎指出!
绪论部分
1.写一个复数抽象类型定义,实现加乘运算
显然对于该问题,只需明确复数的组成包括实部和虚部,再了解复数加法和乘法的运算规则即可求解:
设z1 = a+bi,z2 = c+di(a、b、c、d∈R)是任意两个复数,那么
它们的和是 z1+z2 = (a+c)+(b+d)i,它们的积是z1+z2 = (ac-bd)+(bc+ad)i
编写程序如下:
#include<cstdio>
#include<iostream>
using namespace std;
typedef struct Node
{
int a; //实部;
int b; //虚部;
}Complex;
Complex Add(Complex x,Complex y)
{
Complex res;
res.a = x.a+y.a;
res.b = x.b+y.b;
return res;
}
Complex Multipy(Complex x,Complex y)
{
Complex res;
res.a = x.a*y.a-x.b*y.b;
res.b = x.b*y.a+x.a*y.b;
return res;
}
int main()
{
Complex a,b,c;
cout<<"Enter a and b, represent Complex A = a+bi"<<endl;
cin>>a.a>>a.b;
cout<<"Enter c and d, represent Complex B = c+di"<<endl;
cin>>b.a>>b.b;
c = Add(a,b);
printf("A+B = %d%+di\n",c.a,c.b);
c = Multipy(a,b);
printf("A*B = %d%+di\n",c.a,c.b);
return 0;
}
2.用流程图表示一元二次函数的求解过程(略~)
线性表部分
1.在逻辑层面求两集合的差集
显然对于该问题,由定义设集合A,B,则A与B的差集为:A-B && B-A,根据对称差运算的性质,即可编写程序如下:
#include<cstdio>
#include<iostream>
#define inf -1000000000
using namespace std;
int main()
{
int A[1000],B[1000],m,n;
cout<<"Enter m,n,indicating set A contains m elements,set B contains n elements"<<endl;
cin>>m>>n;
cout<<"Enter "<<m<<" different elems: "<<endl;
for(int i = 0; i < m; i++)
cin>>A[i];
cout<<"Enter "<<n<<" different elems: "<<endl;
for(int i = 0; i < n; i++)
cin>>B[i];
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
if(A[i] == B[j])
{
A[i] = B[j] = inf;
break; //A或B中不该出现重复元素,所以找到直接break;
}
cout<<"A-B: "<<endl;
for(int i = 0; i < m; i++)
if(A[i] != inf)
cout<<A[i]<<" ";
cout<<endl;
cout<<"B-A: "<<endl;
for(int i = 0; i < n; i++)
if(B[i] != inf)
cout<<B[i]<<" ";
cout<<endl;
return 0;
}
2.在顺序表A的第i个元素前插入元素B
顺序表,不用多说,先建立表A,再定位插入位置,最后插入即可
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define INIT_SIZE 100
#define DLC 10
#include<cstdlib>
#include<iostream>
using namespace std;
typedef int Status,ElemType;
typedef struct
{
ElemType *elem;
int length,listsize;
}SqList;
Status initSqlist(SqList &L)
{
L.elem = (ElemType *)malloc(INIT_SIZE*sizeof(ElemType));
if(!L.elem) exit(OVERFLOW);
L.length = 0;
L.listsize = INIT_SIZE;
return OK;
}
Status insertElem(SqList &L,int i,ElemType e)
{
if(i < 1 || i > L.length+1) return ERROR;
if(L.length >= L.listsize)
{
ElemType *newbase = (ElemType *)realloc(L.elem,(L.listsize+DLC)*sizeof(ElemType));
if(!newbase) exit(OVERFLOW);
L.elem = newbase;
L.listsize += DLC;
}
for(int j = L.length; j >= i; j--)
L.elem[j] = L.elem[j-1];
L.elem[i-1] = e;
L.length++;
return OK;
}
int main()
{
int n,m,pos;
ElemType t;
SqList L;
initSqlist(L);
cout<<"Enter n,m:"<<endl;
cin>>n>>m;
cout<<"Enter n elems to form SqList A:"<<endl;
for(int i = 1; i <= n; i++)
{
cin>>t;
insertElem(L,i,t);
}
cout<<"Enter m elems to insert(pos,elem):"<<endl;
for(int i = 0; i < m; i++)
{
cin>>pos>>t;
insertElem(L,pos,t);
}
cout<<"Result:"<<endl;
for(int i = 0; i < L.length; i++)
cout<<L.elem[i]<<" ";
cout<<endl;
return 0;
}
3. 在顺序表A的第i个元素前插入表B
这里可以把B当成一个区间,插入到A,应该先判断是否应该对A进行扩容,然后A中相应元素移位,最后代码如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define INIT_SIZE 100
#define DLC 10
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct Node
{
ElemType *elem;
int length,listsize;
}SqList;
Status initSqList(SqList &L)
{
L.elem = (ElemType *)malloc(INIT_SIZE*sizeof(ElemType));
if(!L.elem) exit(OVERFLOW);
L.length = 0;
L.listsize = INIT_SIZE;
return OK;
}
Status insertElem(SqList &L,int i,ElemType e) //单点插入;
{
if(i < 1 || i > L.length+1) return ERROR;
if(L.length >= L.listsize)
{
ElemType *tmp;
tmp = (ElemType *)realloc(L.elem,(DLC+L.listsize)*sizeof(ElemType));
if(!tmp) exit(OVERFLOW);
L.elem = tmp;
L.listsize += DLC;
}
for(int j = L.length; j >= i; j--)
L.elem[j] = L.elem[j-1];
L.elem[i-1] = e;
L.length++;
return OK;
}
Status insertList(SqList &L,int i,SqList T) //区间插入;
{
if(i < 1 || i > L.length) return ERROR;
if(L.length+T.length >= L.listsize)
{
ElemType *tmp;
tmp = (ElemType *)realloc(L.elem,(T.length+L.listsize+DLC)*sizeof(ElemType));
if(!tmp) exit(OVERFLOW);
L.elem = tmp;
L.listsize += T.length+DLC;
}
for(int j = L.length+T.length-1; j >= i-1+T.length; j--)
L.elem[j] = L.elem[j-T.length];
for(int j = i-1; j < T.length+i-1; j++)
L.elem[j] = T.elem[j-i+1];
L.length += T.length;
return OK;
}
void output(SqList L)
{
for(int i = 0; i < L.length; i++)
cout<<L.elem[i]<<" ";
cout<<endl;
}
int main()
{
int pos,m,n;
SqList L,T;
ElemType e;
initSqList(L);
initSqList(T);
cout<<"Enter m,n, indicating SqList A contains m elems, B contains n elems:"<<endl;
cin>>m>>n;
cout<<"Enter "<<m<<" elems for A:"<<endl;
for(int i = 1; i <= m; i++)
{
cin>>e;
insertElem(L,i,e);
}
cout<<"Enter "<<n<<" elems for B:"<<endl;
for(int i = 1; i <= n; i++)
{
cin>>e;
insertElem(T,i,e);
}
cout<<"Enter a position, at where you want B in A:"<<endl;
cin>>pos;
cout<<"Results:"<<endl;
if(insertList(L,pos,T))
output(L);
else cout<<"ERROR!"<<endl;
return 0;
}
4.对于顺序表A,删除从位置i起的连续k个元素
这个,也是非常简单的一个模拟,只需要找到第i个元素,将之后所有元素向前移动k位即可,注意最后顺序表长度的修改!
代码如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define INIT_SIZE 100
#define DLC 10
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct Node
{
ElemType *elem;
int length,listsize;
}SqList;
Status initSqList(SqList &L)
{
L.elem = (ElemType *)malloc(INIT_SIZE*sizeof(ElemType));
if(!L.elem) exit(OVERFLOW);
L.length = 0;
L.listsize = INIT_SIZE;
return OK;
}
Status insertElem(SqList &L,int i,ElemType e) //单点插入;
{
if(i < 1 || i > L.length+1) return ERROR;
if(L.length >= L.listsize)
{
ElemType *tmp;
tmp = (ElemType *)realloc(L.elem,(DLC+L.listsize)*sizeof(ElemType));
if(!tmp) exit(OVERFLOW);
L.elem = tmp;
L.listsize += DLC;
}
for(int j = L.length; j >= i; j++)
L.elem[j] = L.elem[j-1];
L.elem[i-1] = e;
L.length++;
return OK;
}
Status deleteRange(SqList &L,int i,int k) //区间删除;
{
if(i < 1 || i+k > L.length+1) return ERROR;
for(int j = i-1; j < L.length; j++)
L.elem[j] = L.elem[j+k];
L.length -= k;
return OK;
}
void output(SqList L)
{
for(int i = 0; i < L.length; i++)
cout<<L.elem[i]<<" ";
cout<<endl;
}
int main()
{
int pos,n,range;
SqList L;
ElemType e;
initSqList(L);
cout<<"Enter n, indicating SqList A contains n elems:"<<endl;
cin>>n;
cout<<"Enter "<<n<<" elems:"<<endl;
for(int i = 1; i <= n; i++)
{
cin>>e;
insertElem(L,i,e);
}
cout<<"Enter i,k, to delete range[i,i+k):"<<endl;
cin>>pos>>range;
cout<<"Results:"<<endl;
if(deleteRange(L,pos,range))
output(L);
else cout<<"ERROR!"<<endl;
return 0;
}
5.统计单链表中值为x的元素个数
这个题目,呃,就是把遍历函数改一下加个计数器就好了,代码如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status creatLinkList(LinkList &L)
{
int n;
L = (LinkList)malloc(sizeof(LNode));
if(!L) exit(OVERFLOW);
L->data = 0;
LinkList Tail = L; //尾指针;
Tail->next = nullptr;
cout<<"Enter n:"<<endl;
cin>>n;
cout<<"Enter "<<n<<" elems to insert:"<<endl;
while(n--)
{
LinkList tmp = (LinkList)malloc(sizeof(LNode));
if(!tmp) exit(OVERFLOW);
cin>>tmp->data;
Tail->next = tmp;
Tail = tmp;
tmp = nullptr;
L->data++;
}
Tail->next = nullptr;
return OK;
}
int countX(LinkList L,ElemType x) //计数;
{
int cnt = 0;
L = L->next;
while(L)
{
if(L->data == x) cnt++;
L = L->next;
}
return cnt;
}
int main()
{
ElemType x;
LinkList L;
creatLinkList(L);
cout<<"Enter x:"<<endl;
cin>>x;
cout<<"The number of "<<x<<" in LinkList:"<<endl;
cout<<countX(L,x)<<endl;
return 0;
}
6.删除单链表中相同元素
这个题目,可以嵌套循环,第一层循环遍历链表,在第i个节点记录T->data,内层循环从i+1一直到表尾,用j作计数器,当找到和T->data相等的元素时,就删除第i+j个节点,反复如此直到循环结束即可,代码如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status creatLinkList(LinkList &L)
{
int n;
L = (LinkList)malloc(sizeof(LNode));
if(!L) exit(OVERFLOW);
L->data = 0;
LinkList Tail = L; //尾指针;
Tail->next = nullptr;
cout<<"Enter n:"<<endl;
cin>>n;
cout<<"Enter "<<n<<" elems to insert:"<<endl;
while(n--)
{
LinkList tmp = (LinkList)malloc(sizeof(LNode));
if(!tmp) exit(OVERFLOW);
cin>>tmp->data;
Tail->next = tmp;
Tail = tmp;
tmp = nullptr;
L->data++;
}
Tail->next = nullptr;
return OK;
}
Status deleteElem(LinkList L,int i,ElemType &e) //单点删除;
{
if(i < 1 || i > L->data) return ERROR;
L->data--;
while(i > 1)
{
i--;
L = L->next;
}
LinkList tmp = L->next;
e = tmp->data;
L->next = tmp->next;
free(tmp);
return OK;
}
Status deleteSameElems(LinkList L) //重复元素删除;
{
int i = 1;
ElemType e;
LinkList p = L->next;
while(p)
{
int j = 1;
ElemType tmp = p->data;
LinkList t = p->next;
while(t)
{
if(t->data == tmp)
{
deleteElem(L,i+j,e);
cout<<e<<" has been deleted!"<<endl;
}
else j++;
t = t->next;
}
p = p->next;
i++;
}
return OK;
}
void Traverse(LinkList L)
{
L = L->next;
while(L)
{
cout<<L->data<<" ";
L = L->next;
}
cout<<endl;
}
int main()
{
ElemType e;
LinkList L;
creatLinkList(L);
deleteSameElems(L);
cout<<"Remaining LinkList:"<<endl;
Traverse(L);
return 0;
}
PS: 讲点题外话,今天上课学了一个有点意思的算法:单链表的转置,实际上是使用三个指针不断移动达到转置的效果,算法时间复杂度很优秀,为O(n),空间复杂度为O(1),实现如下:
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#include<iostream>
#include<cstdlib>
using namespace std;
typedef int Status,ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status creatLinkList(LinkList &L)
{
int n;
ElemType e;
L = (LinkList)malloc(sizeof(LNode));
if(!L) exit(OVERFLOW);
L->data = 0;
LinkList Tail = L; //尾指针;
Tail->next = nullptr;
cout<<"Enter n:"<<endl;
cin>>n;
cout<<"Enter "<<n<<" elems to insert:"<<endl;
while(n--)
{
LinkList tmp = (LinkList)malloc(sizeof(LNode));
if(!tmp) exit(OVERFLOW);
cin>>tmp->data;
Tail->next = tmp;
Tail = tmp;
tmp = nullptr;
L->data++;
}
Tail->next = nullptr;
return OK;
}
void reverseLinkList(LinkList &L)
{
if(L->data < 2) return;
LinkList p,q,r;
p = L->next;
q = p->next;
r = q->next;
p->next = nullptr; //修改表尾;
while(q->next)
{
q->next = p;
p = q;
q = r;
r = r->next;
}
q->next = p; //处理表尾;
L->next = q; //修改头指针;
}
void Traverse(LinkList L)
{
L = L->next;
while(L)
{
cout<<L->data<<" ";
L = L->next;
}
cout<<endl;
}
int main()
{
ElemType e;
LinkList L;
creatLinkList(L);
cout<<"Before reversing:"<<endl;
Traverse(L);
reverseLinkList(L);
cout<<"After reversing:"<<endl;
Traverse(L);
return 0;
}
栈和队列部分
1.用栈实现括号配对
哇塞这么经典的题目!南阳OJ了解一下?——括号配对问题,不多说了,AC代码献上:
#include<iostream>
#include<cstdlib>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define INIT_SIZE 100
#define DLC 10
typedef int Status;
typedef char ElemType;
using namespace std;
typedef struct Stack
{
ElemType *base;
ElemType *top;
int _size;
}Stack;
Status initStack(Stack &S)
{
S.base = (ElemType *)malloc(INIT_SIZE*sizeof(ElemType));
if(!S.base) exit(OVERFLOW);
S.top = S.base;
S._size = INIT_SIZE;
return OK;
}
inline int getLength(Stack S)
{
return S.top-S.base;
}
inline void clearStack(Stack &S)
{
S.top = S.base;
S._size = INIT_SIZE;
}
Status push(Stack &S,ElemType e)
{
int len = getLength(S);
if(len >= S._size)
{
S.base = (ElemType *)realloc(S.base,(S._size+DLC)*sizeof(ElemType));
if(!S.base) exit(OVERFLOW);
S._size += DLC;
}
*S.top++ = e;
return OK;
}
Status top(Stack S,ElemType &e)
{
if(!getLength(S)) return ERROR;
e = *(S.top-1);
return OK;
}
Status pop(Stack &S)
{
if(!getLength(S)) return ERROR;
S.top--;
return OK;
}
int main()
{
int n;
cin>>n;
Stack S;
ElemType *e,tmp,E[10000];
initStack(S);
while(n--)
{
e = E;
cin>>E;
clearStack(S);
while(*(e) != '\0')
{
tmp = '@'; //解决程序中的bug;
if(*(e) == '(' || *(e) == '[')
push(S,*(e));
else if(*(e) == ')')
{
top(S,tmp);
if(tmp == '(') pop(S);
else break;
}
else if(*(e) == ']')
{
top(S,tmp);
if(tmp == '[') pop(S);
else break;
}
e++;
}
if(getLength(S) || *e != '\0') cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
return 0;
}
2.用栈判断回文串
这个题目一般两个思路,一个是把字符串全部入栈,出栈时再和原字符串比较,若一一对应,则是回文串,另一思路是,递归判断,不过跟栈没什么关系(如果递归栈也算的话那就另当别论),就不写了,实现一下思路一:
#include<iostream>
#include<cstring>
#include<cstdio>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define INIT_SIZE 100
#define DLC 10
typedef int Status;
typedef char ElemType;
using namespace std;
typedef struct Stack
{
ElemType *base;
ElemType *top;
int _size;
}Stack;
Status initStack(Stack &S)
{
S.base = (ElemType *)malloc(INIT_SIZE*sizeof(ElemType));
if(!S.base) exit(OVERFLOW);
S.top = S.base;
S._size = INIT_SIZE;
return OK;
}
inline int getLength(Stack S)
{
return S.top-S.base;
}
inline void clearStack(Stack &S)
{
S.top = S.base;
S._size = INIT_SIZE;
}
Status push(Stack &S,ElemType e)
{
int len = getLength(S);
if(len >= S._size)
{
S.base = (ElemType *)realloc(S.base,(S._size+DLC)*sizeof(ElemType));
if(!S.base) exit(OVERFLOW);
S._size += DLC;
}
*S.top++ = e;
return OK;
}
Status top(Stack S,ElemType &e)
{
if(!getLength(S)) return ERROR;
e = *(S.top-1);
return OK;
}
Status pop(Stack &S)
{
if(!getLength(S)) return ERROR;
S.top--;
return OK;
}
int main()
{
Stack S;
ElemType *e,tmp,E[1000];
initStack(S);
cout<<"Enter string: "<<endl;
while(cin>>E)
{
e = E;
clearStack(S); //每次清空;
while(*(e) != '\0')
{
push(S,*e);
e++;
}
e -= strlen(E); //指针应该回到开始位置;
while(*(e) != '\0')
{
top(S,tmp);
if(tmp == *(e)) pop(S);
else break;
e++;
}
if(*e != '\0') cout<<"Non-Palindrome!"<<endl; //e没有遍历至结束,表示字符串不是对称结构,非回文;
else cout<<"Palindrome!"<<endl;
}
return 0;
}
3.求链队列的结点数
先构造链队列,再从头遍历到尾计数即可,实现如下:
#include<iostream>
#include<cstring>
#define OVERFLOW -2
using namespace std;
typedef struct node
{
char data;
struct node *next;
}LQueue,*LQueuePtr;
typedef struct LQueueNode
{
LQueuePtr Front,Rear;
}LinkQueue;
bool initLQueue(LinkQueue &Q) //初始化;
{
Q.Front = Q.Rear = (LQueuePtr)malloc(sizeof (LQueue));
if(!Q.Front) exit(OVERFLOW);
Q.Rear->next = nullptr;
return 1;
}
bool Push(LinkQueue &Q,char e) //入队;
{
LQueuePtr p = (LQueuePtr)malloc(sizeof (LQueue));
if(!p) exit(OVERFLOW);
p->data = e;
p->next = nullptr;
Q.Rear->next = p;
Q.Rear = p;
return 1;
}
bool Pop(LinkQueue &Q) //出队;
{
if(Q.Front == Q.Rear) return 0;
LQueuePtr p = Q.Front;
Q.Front = Q.Front->next;
free(p);
return 1;
}
bool Top(LinkQueue Q,char &e) //取队首;
{
if(Q.Front == Q.Rear) return 0;
e = Q.Front->next->data;
return 1;
}
int elem_Num(LinkQueue Q) //队列结点数;
{
int sum = 0;
while(Q.Front != Q.Rear)
{
Q.Front = Q.Front->next;
sum++;
}
return sum;
}
int main()
{
int n,l;
char e;
LinkQueue Q;
initLQueue(Q);
cin>>n;
while(n--)
{
cin>>e;
Push(Q,e);
}
cout<<elem_Num(Q)<<endl;
while(Q.Front != Q.Rear)
{
Top(Q,e);
cout<<e<<endl;
Pop(Q);
}
return 0;
}
树和图论部分
1.判断二叉树的深度
构造二叉树,递归判断即可,Depth(T) = max(Depth(T->lc),Depth(T->rc))+1;实现如下:
#include<iostream>
#include<algorithm>
using namespace std;
typedef struct node
{
char data;
struct node *lc,*rc;
}*BTT,BTTNode;
void initBTT(BTT &T) //先序构造二叉树;
{
char ch;
cin>>ch;
if(ch == '@')
{
T = nullptr;
return;
}
T = new BTTNode;
T->data = ch;
initBTT(T->lc);
initBTT(T->rc);
}
void preOrderTraverse(BTT T) //先序遍历;
{
if(T == nullptr) return;
cout<<T->data;
preOrderTraverse(T->lc);
preOrderTraverse(T->rc);
}
void inOrderTraverse(BTT T) //中序遍历;
{
if(T == nullptr) return;
inOrderTraverse(T->lc);
cout<<T->data;
inOrderTraverse(T->rc);
}
void postOrderTraverse(BTT T) //后序遍历;
{
if(T == nullptr) return;
postOrderTraverse(T->lc);
postOrderTraverse(T->rc);
cout<<T->data;
}
inline bool isLeaf(BTT T) //判断叶子;
{
return (T->lc == nullptr && T->rc == nullptr);
}
int BTT_Depth(BTT T) //树深;
{
if(isLeaf(T)) return 1;
return max(BTT_Depth(T->lc),BTT_Depth(T->rc))+1;
}
int leaf_Num(BTT T) //统计叶子数;
{
if(isLeaf(T)) return 1;
return leaf_Num(T->lc)+leaf_Num(T->rc);
}
int node_Num(BTT T) //统计节点数;
{
if(T == nullptr) return 0;
return node_Num(T->lc)+node_Num(T->rc)+1;
}
void destory_BTT(BTT &T) //销毁二叉树;
{
if(T == nullptr) return;
destory_BTT(T->lc);
destory_BTT(T->rc);
delete T;
T = nullptr;
}
int main()
{
BTT T;
initBTT(T);
preOrderTraverse(T);
cout<<endl;
inOrderTraverse(T);
cout<<endl;
postOrderTraverse(T);
cout<<endl;
cout<<node_Num(T)<<endl;
cout<<BTT_Depth(T)<<endl;
cout<<leaf_Num(T)<<endl;
destory_BTT(T);
if(T == nullptr) cout<<"Yes"<<endl;
else cout<<"Error"<<endl;
return 0;
}
2.画一个图的邻接矩阵和邻接表并求每个点的度,就不画了,有兴趣可以看看我写的邻接表和邻接矩阵