今天 我决定开启我的数据结构之路,话说虽然我学的是电子信息类,但是其实也要用到计算机,哎 老师说数据结构是计算机专业的核心课程 好吧 我今天就开始啃这个硬核,项目先不做。先注重把这些基础夯实就行了。
其实真的在学习之前,想一下你为啥要学这个,是闲的蛋疼吗,我相信肯定知道学这个好,有用处,你才来学,那好在哪里,你有清楚吗。很多人慌着去赶紧开始正文,其实真的欲速则不达,你都没有弄清初心,后面一定会出问题的。而且也不是,模糊的知道好 反正就是好,好个屁,你的大脑会说,反正我不知道 是咋好,你爱咋咋。在三分钟热度过后,自然凉凉。
为啥要学习数据结构和算法
数据结构代表一种批量存储数据的方式,强调的是逻辑思维
1. 链表
链表其实就是结构体和结构体链接在一起。
而结构体是数据域和指针域结合在一起。
定义链表表头和 节点
定义链表实际就是创建一个表头,表头只是一个特殊的节点罢了,里面不存数据。就这一点不同。我们用
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
来创建新的节点,节点就是一个结构体变量,但是里面包含指针变量。
//有头链表:表头不存放数据去操作
//其实表头就是一个结构体变量,里面包含指针
所以说最重要的是定义一个指针变量
struct Node * createlist()
{//指针---》变成变量 指针指向变量的开头地址
//动态内存申请
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//这是一个变量 我们需要去赋值
//表头不存数据 但是指针我们要定义
headNode->next = NULL;
//开始的时候,表头只有表头,表头没有下一个
return headNode;
}
//创建节点:为插入数据和指针做准备
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
};
//定义表头和节点的方式是一样的,只是我们区别对待
我发现其实链表也不是很难,当时学的时候只不过没有人给我细讲,把逻辑搞顺了,就自然而然的写出来了。
用语言表示他们的关系 在弄一个或两个移动至真 来查找遍历,就可以了
不能通过下标去访问,只能通过指针去访问
插入节点
头插法
下面我们来讲一下节点之间的连接与插入。
先连后断。头结点后面的空间不管你是否插入新的节点,他都叫head->next
第一步 新节点的下一个指向头结点的下一个
第二步 让头结点的下一个指向新节点
最后 在更换指向的时候 原来的黑线就断掉了
//表头法插入 头插法
void insertBh(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data);//先创建新的节点
newNode->next = headNode->next;
headNode->next = newNode;
}
打印列表
void printCreatelist(struct Node* headNode)
{
struct Node* pMove = headNode->next;//定义动态指针, 让他先指着第一个节点 就是头结点的后面
while (pMove)
{
printf("%d---->", pMove->data);
pMove = pMove->next;
}
}
在这里我们需要定义一个动态指针,当是有头列表时,我们从第一个节点开始打印,先判断列表是否为空,不为空,则把里面的数据打印出来,然后让动态指针pMove 向后移动 即pMove=pMove->next;再次判断
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node* next;
};
//有头链表:表头不存放数据去操作
//其实表头就是一个结构体变量
struct Node * createlist()
{//指针---》变成变量 指针指向变量的开头地址
//动态内存申请
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//这是一个变量 我们需要去赋值
//表头不存数据 但是指针我们要定义
headNode->next = NULL;
//开始的时候,表头只有表头,表头没有下一个
return headNode;
}
//创建节点:为插入数据和指针做准备
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
};
//定义表头和节点的方式是一样的,只是我们区别对待
//表头法插入 头插法
void insertBh(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data);
newNode->next = headNode->next;
headNode->next = newNode;
}
void printCreatelist(struct Node* headNode)
{
struct Node* pMove = headNode->next;//定义动态指针, 让他先指着第一个节点 就是头结点的后面
while (pMove)
{
printf("%d---->", pMove->data);
pMove = pMove->next;
}
}
int main()
{
struct Node* list = createlist();//封装上述功能来创建列表
insertBh(list, 1);
insertBh(list, 2);
insertBh(list, 3);
printCreatelist(list);
system("pause");
}
尾插法
先创建一个新的节点
最后一个指向的一定是NULL 所以我们要用这样一个标志先找到尾部。
在找尾部后,我们让尾部指向新的节点 ,因为新的节点就是指向NULL的。很简单
//尾插法
void insertBt(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data);
struct Node* tailNode = headNode;
while (tailNode->next!=NULL)
{
tailNode = tailNode->next;
}
tailNode->next = newNode;
}
指定位置插入
//在任意位置插入节点。
//struct Node* headNode,;指定的是哪一个链表
//int data :新节点插入的数据
//int sub :指定位置
void insertAny(struct Node* headNode, int data, int sub)
{
struct Node* posFroNode = headNode;
struct Node* posNode = headNode->next;
//当当前指针的值不为NULL时,并且当前节点中的元素并不是查找元素
//在这里我们需要两个动态指针去向后传递 当所在位置不为空也不是想要找的位置时,继续向下移动
while (posNode != NULL&&posNode->data != sub)
{
posFroNode = posNode;
posNode = posNode->next;
}
//分析posNode的状态。
if (posNode == NULL)//说明到末尾了 还没有找到
{
printf("未找到相应位置");
}
else//找到了指定位置 ,我们就来创建新的节点插入
{
struct Node* newNode = createNode(data);
posFroNode->next = newNode;
newNode->next = posNode;
}
}
到这里 小结一下 三种插入方法讲述完毕,
头插法 ----》尾插法-----》指定位置插入
删除节点
其实我们想要找到一个位置,就要先找到他前面的那一个位置 成为FrontPos 那么FrontPos后面的位置nextNode就是我们想要找的Position.
我们 就给位置指针起一个名字叫做nextNode,然后直接让FrontNode指向nextNode的后面,再把它释放掉空间就行了。
太好了,视频上面讲的是删除掉表头后面第一个节点,不过那样真的没啥用,我懂了思路以后自己试了一下,很简单,成功了,能够删除任意位置的节点,对了,我刚才一直难受,我后来想了半天,感觉是眼镜的事,戴着那个防蓝光眼镜很难受,摘了试试。
可能真的有问题 好害怕。
删除操作一定要先判断是否为空。
//删除节点
//删除的链表的头节点是headNode,里面的数据是data。
void deleteJd(struct Node* headNode, int data)
{
struct Node* posFroNode = headNode;
struct Node* posNode = headNode->next;
//当当前指针的值不为NULL时,并且当前节点中的元素并不是查找元素
//在这里我们需要两个动态指针去向后传递 当所在位置不为空也不是想要找的位置时,继续向下移动
while (posNode != NULL&&posNode->data != data)
{
posFroNode = posNode;
posNode = posNode->next;
}
//分析posNode的状态。
if (posNode == NULL)//说明到末尾了 还没有找到
{
printf("未找到相应位置");
}
else//找到了指定位置 ,我们就来删除节点
{
posFroNode->next = posNode->next;
free(posNode);
}
}
终于学完了单链表的操作 总之就是
知识点有:头插法,尾插法,任意位置插入。 还有打印,删除,那么其实只要原理懂了,啥都不难。
最终程序
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int data;
struct Node* next;
};
//有头链表:表头不存放数据去操作
//其实表头就是一个结构体变量
struct Node * createlist()
{//指针---》变成变量 指针指向变量的开头地址
//动态内存申请
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//这是一个变量 我们需要去赋值
//表头不存数据 但是指针我们要定义
headNode->next = NULL;
//开始的时候,表头只有表头,表头没有下一个
return headNode;
}
//创建节点:为插入数据和指针做准备
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
};
//定义表头和节点的方式是一样的,只是我们区别对待
//表头法插入 头插法
void insertBh(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data);
newNode->next = headNode->next;
headNode->next = newNode;
}
//尾插法
void insertBt(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data);
struct Node* tailNode = headNode;
while (tailNode->next!=NULL)
{
tailNode = tailNode->next;
}
tailNode->next = newNode;
}
//在任意位置插入节点。
//struct Node* headNode,;指定的是哪一个链表
//int data :新节点插入的数据
//int sub :指定位置
void insertAny(struct Node* headNode, int data, int sub)
{
struct Node* posFroNode = headNode;
struct Node* posNode = headNode->next;
//当当前指针的值不为NULL时,并且当前节点中的元素并不是查找元素
//在这里我们需要两个动态指针去向后传递 当所在位置不为空也不是想要找的位置时,继续向下移动
while (posNode != NULL&&posNode->data != sub)
{
posFroNode = posNode;
posNode = posNode->next;
}
//分析posNode的状态。
if (posNode == NULL)//说明到末尾了 还没有找到
{
printf("未找到相应位置");
}
else//找到了指定位置 ,我们就来创建新的节点插入
{
struct Node* newNode = createNode(data);
posFroNode->next = newNode;
newNode->next = posNode;
}
}
//删除节点
//删除的链表的头节点是headNode,里面的数据是data。
void deleteJd(struct Node* headNode, int data)
{
struct Node* posFroNode = headNode;
struct Node* posNode = headNode->next;
//当当前指针的值不为NULL时,并且当前节点中的元素并不是查找元素
//在这里我们需要两个动态指针去向后传递 当所在位置不为空也不是想要找的位置时,继续向下移动
while (posNode != NULL&&posNode->data != data)
{
posFroNode = posNode;
posNode = posNode->next;
}
//分析posNode的状态。
if (posNode == NULL)//说明到末尾了 还没有找到
{
printf("未找到相应位置");
}
else//找到了指定位置 ,我们就来删除节点
{
posFroNode->next = posNode->next;
free(posNode);
}
}
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;//定义动态指针, 让他先指着第一个节点 就是头结点的后面
while (pMove)
{
printf("%d---->", pMove->data);
pMove = pMove->next;
}
printf("\n");
}
int main()
{
struct Node* list = createlist();//封装上述功能来创建列表
for (int i=0; i < 10; i++)
{
insertBh(list, i);
}
printList(list);
insertBt(list, 999);
printList(list);
insertAny(list, 100,999);
printList(list);
deleteJd(list, 5);
printList(list);
system("pause");
return 0;
}
说个闲话,回到正常比例:Ctrl+0
VS Ctrl+enter
项目 管理系统
链表其实就是一个容易,特别适合去做一个
管理系统:增—删---改----查
Q:system(“pause”);是什么意思
也可以这样,看起来调理也很清析
错误1:
Q:为啥 定义表头和节点 是要定义一个指针变量
因为定义链表的节点的时候,我们都是定义指针变量,如果你采用局部变量,就会被销毁,我们这样做你在函数里面工作后,离开也不会销毁,我们想销毁的时候在做
Q:
无头链表
其实无头链表和单链表比起来就是第一个表头里面有数据。
头插法
动态指针需要不停的指向新的节点,动态指针指向谁,谁就是表头
我们先创建新的节点,然后让新的节点的next指向原来的表头,让动态指针指向表头。
总之,不断地插入表头(新节点),你插入的数据自然头插了。
最开始列表里啥都没有,等于NULL,然后创建头结点list,头插法,在创建一个新节点,新节点指向原来的头结点,头节点指向新节点。总之,list头结点一直指向新的节点。
#include<stdio.h>
#include<stdlib.h>
//无头链表就是第一个表头中放了数据
//二级指针方法
//
int data;
struct Node** headNode = NULL;
struct Node
{
int data;
struct Node* next;
};
struct Node* createList(int data)
{
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
headNode->data = data;
headNode->next = NULL;
return headNode;
}
struct Node* createNew(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
void insertBt(struct Node** headNode,int data)
{
struct Node* newNode = createNew(data);//创建新的节点
newNode->next =(*headNode);//然后新的节点指向原来的表头
(*headNode) = newNode;//原来的表头指向新的节点
}
void printList(struct Node* headNode)
{
struct Node* pMove = headNode;
while (pMove)
{
printf("%d------》", pMove->data);
pMove = pMove->next;
}
printf("\n");
}
int main()
{
struct Node* list=createList(data);
insertBt(&list, 2);//因为我们要传递的是二级指针,所以写一级指针的地址
insertBt(&list, 3);
printList(list);
system("pause");
return 0;
}
真的吓死了,我刚才不小心在VS上点了排除该项目,就把一个cpp文件删掉了,我再想恢复,查了网上的方法,发现那个文件都变成obj文件了,真是的,
不过后来关闭,发现可以不保存操作,太好了。
栈
问题:那个表头和表位都还没给空间 那我指的第三句只是把名字换一下对吗
错误2:释放空间顺序错误
栈的程序
/*
栈是先进后出,后来居上的一种数据存储结构
栈的基本属性:栈中的元素个数 栈顶标记 栈内存
栈的基本操作: 入栈;向栈内添加元素
出栈:删除栈内元素
获取栈顶元素:栈顶标记的元素
万金油操作:
判断是否为NULL,
当前栈中的数据个数
根据实现的方式:
我们分为
链式栈:
数组栈
*/
#include<stdio.h>
#include<stdlib.h>
//链表结构
struct Node
{
int data;
struct Node* next;
};
struct Node* createNew(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
//栈结构
struct stack
{
struct Node* stackTop;//栈顶标记用指针去表示
int stackSize;//栈的当前数据个数
};
//万金油函数
int size(struct stack* pStack)
{
return pStack->stackSize;
}
int empty(struct stack* pStack)
{
return pStack->stackSize == 0;//当stackSize为1时 不等于0,就返回1
}
//创建栈 跟创建链表很像啊
struct stack* createStack()
{
struct stack* pStack = (struct stack*)malloc(sizeof(struct stack));
pStack->stackSize = 0;
pStack->stackTop = NULL;
return pStack;
}
//入栈--等于头插法 无头链表
void push(struct stack* pStack, int data)
{
struct Node* newNode = createNew(data);
newNode->next = pStack->stackTop;
pStack->stackTop = newNode;
pStack->stackSize++;//数量加1
}
//出栈和头删法一样
void pop(struct stack* pStack)
{
if (pStack->stackSize == 0)
{
printf("此栈为NULL");
return;
}
struct Node* nextNode = pStack->stackTop->next;//先保存头部指针的后面的信息
free(pStack->stackTop);//堆内存实现的栈结构,需要手动释放 除了数值这种变量
pStack->stackTop = nextNode;//然后移动栈顶指向后一
pStack->stackSize--;
}
//输出栈顶数值
int stackTop(struct stack* pStack)
{
return pStack->stackTop->data;//返回栈顶的值
}
int main()
{
struct stack* newStack = createStack();
push(newStack, 1);
push(newStack, 2);
push(newStack, 3);
while (!empty(newStack))
{
printf("%d--->", stackTop(newStack));
pop(newStack);
}
system("pause");
return 0;
}
总之,上面要先入栈,在出栈,后来居上,先进后出。输出的都是栈顶元素
下面这个就是我经常错的
栈:头插头取
队列:尾插头取
队列的代码
#include<stdio.h>
#include<stdlib.h>
struct Node//节点设置
{
int data;
struct que* next;
};
struct que
{
int size;//内存数据个数
struct Node* froNode;//头指针
struct Node* tailNode;//尾部指针
};
//创建队列
struct que* createList()
{
struct que* list = (struct que*)malloc(sizeof(struct que));
if (empty(list))
{
printf("队列创建失败");
}
//初始化 队列
list->size = 0;
list->froNode = NULL;
list->tailNode = NULL;
return list;
}
//创建节点
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
//求队列大小
int size(struct que* list)
{
return list->size;
}
//判断队列是否为空
int empty(struct que* list)
{
return list->size == 0;
}
//入队
void push(struct que* list, int data)
{
struct Node* newNode = createNode(data);
if (empty(list))//判断是否为空
{//因为只有一个节点,那么他既是队头又是队尾。
list->froNode = newNode;
list->tailNode = newNode;
}
else
{
list->tailNode->next = newNode;//先连接上新节点
list->tailNode = newNode;//然后让尾部往后移动
}
list->size++;//记得让数量加1;
}
//出队
void pop(struct que* list)
{
if (!empty(list))
{
struct Node* popNode = list->froNode;
list->froNode = popNode->next;
free(popNode);
list->size--;
}
}
//返回队的前部元素
int queFro(struct que* list)
{
return list->froNode->data;
}
int main()
{
struct que* list = createList();
push(list, 2);
push(list, 3);
push(list, 4);
while (!empty(list))
{
printf("%d------>", queFro(list));
pop(list);
}
system("pause");
return 0;
}
一级指针
妈呀 昨天没保存,真是伤感,啊哈哈哈,不过,我发现我现在要解决的不是dfs,而是
邻接矩阵
一维数组里面存放顶点,二维数组是一个方阵,长和宽都是顶点个数,单向6条边,实际有12条,因为a->c,那么c->a,Ok。中间的对角线是0,因为自己不能成边,
邻接表
每个顶点都是头,作为首地址,后面带着一个链表,身体都是与他相连的顶点。
二级指针描述二维数组
一个指针指向一块区域,里面有很多成员指针,而里面的每一个指针又指向新的一块区域。
src 起点 dst 终点
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string.h>
#define WUXIANG 1
using namespace std;
//图结构
struct Graph
{
int vertexs;//顶点个数
int edges;//边的个数
char* pVertex;//用来存储所有顶点
//为蛇魔一个char* 指针就能存储所有顶点呢?
//因为一个指针可以指向一块连续的地址的首地址,我们有vertexs。
int ** ppEdge;//使用二级指针来描述二维数组。
};
//C++ 不用写struct
Graph* createGraph();//创建一个图,并返回该图的首地址
void initGraph(Graph* graph);
void destroyGraph(Graph * graph);
int _getIndex(Graph*graph, char c);//带下划线都是内部使用函数
//把图和顶点传进去,
void show(Graph *graph);
int main()
{
//创建图对象
Graph *graph = createGraph();
//初始化
initGraph(graph);
//显示图
show(graph);
destroyGraph(graph);
system("pause");
/*while (1);*/
return 0;
}
Graph* createGraph()
{
//结构
Graph* graph = new Graph;//先把结构开起来
//内容
graph->edges = graph->vertexs = 0;
graph->ppEdge = NULL;
graph->pVertex = NULL;
//一行代码搞定
//memset(graph, 0, sizeof(Graph));
return graph;
}
void initGraph(Graph* graph)
{
cout << "输入顶点个数" << endl;
cin >> graph->vertexs;
cout << "输入边的个数" << endl;
cin >> graph->edges;
//开内存
graph->pVertex = new char[graph->vertexs+1];//保存顶点的一位数组
//保存描述边的二维数组
graph->ppEdge = new int*[graph->vertexs];
for (int i = 0; i < graph->vertexs; i++)
{
graph->ppEdge[i] = new int[graph->vertexs];
memset(graph->ppEdge[i], 0, sizeof(int)*graph->vertexs);
}
//赋值
cout << "请输入顶点:" << endl;
scanf("%s", graph->pVertex);//自己写就这样写,给别人用,就写循环
//对于一段内存的输入,都是找到首地址
/*while (cin >> graph->pVertex)
{
}*/
char buff[5] = { 0 };
int srcIdx, dstIdx;
for (int i = 0; i < graph->edges; i++)
{
cout << "请输入第" << i + 1 << "条边(A->B):" ;
scanf("%s", buff);
srcIdx = _getIndex(graph, buff[0]);
dstIdx = _getIndex(graph, buff[3]);
graph->ppEdge[srcIdx][dstIdx] = 1;
//如果加了无向图
//#if WUXIANG
graph->ppEdge[dstIdx][srcIdx] = 1;
//#endif
}
}
//返回顶点在图中下标,如果没有这个顶点,就返回-1
int _getIndex(Graph* graph, char c)
{
for (int i = 0; i < graph->vertexs; i++)
{
if (c == graph->pVertex[i]) return i;
}
return -1;
}
//打印图
void show(Graph* graph)
{
for (int i = 0; i <= graph->vertexs; i++){
for (int j = 0; j <= graph->vertexs; j++){
if (i == 0 && j == 0)//左上角空置
cout << " ";
else if (i == 0){
printf("%c ", graph->pVertex[j - 1]);
}
else if (j == 0){
printf("%c ", graph->pVertex[i - 1]);
}
else{
printf("%d ", graph->ppEdge[i - 1][j - 1]);
}
}
printf("\n");
}
}
void destroyGraph(Graph * graph)
{
}
//#include<iostream>
//#include<vector>
//using namespace std;
//#define N 10005
//int n, m, ans;
//vector<int> mp[N];
//void dfs(int last, int x, int num) //因为只有四个点,而第一个和最后一个点可以相同,所以只要保证每个点和它上上个点不同即可(它和上个点一定不同,因为存在一条边)
//{
// if (num == 3)
// {
// ans++; return;
// }
// for (int i = 0; i<mp[x].size(); i++)
// {
// if (mp[x][i] != last)
// {
// dfs(x, mp[x][i], num + 1);
// }
// }
//}
//int main()
//{
// scanf("%d%d", &n, &m);
// for (int i = 0; i<m; i++)
// {
// int u, v;
// scanf("%d%d", &u, &v);
// mp[u].push_back(v);
// mp[v].push_back(u);
// }
// for (int i = 1; i <= n; i++)
// {
// dfs(-1, i, 0);
// }
// cout << ans << endl;
// return 0;
//}
偷过懒之后,啊啊,就是重载那个初始化函数。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string.h>
#define WUXIANG 1
#define VERTEXS 6
using namespace std;
//图结构
struct Graph
{
int vertexs;//顶点个数
int edges;//边的个数
char* pVertex;//用来存储所有顶点
//为蛇魔一个char* 指针就能存储所有顶点呢?
//因为一个指针可以指向一块连续的地址的首地址,我们有vertexs。
int ** ppEdge;//使用二级指针来描述二维数组。
};
//C++ 不用写struct
Graph* createGraph();//创建一个图,并返回该图的首地址
void initGraph(Graph* graph);
void initGraph(Graph* graph, int vertexs, int lines, char* str, int map[VERTEXS][VERTEXS]);
void destroyGraph(Graph * graph);
int _getIndex(Graph*graph, char c);//带下划线都是内部使用函数
//把图和顶点传进去,
void show(Graph *graph);
int main()
{
char buff[] = "ABCDEF";
int map[VERTEXS][VERTEXS] = {//二维数组,初始化
{ 0, 0, 1, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0 },
{ 1, 1, 0, 1, 1, 1 },
{ 0, 0, 1, 0, 1, 0 },
{ 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 0, 0, 0 }
};
//创建图对象
Graph *graph = createGraph();
//初始化
initGraph(graph, VERTEXS, 6, buff, map);
/*initGraph(graph);*/
//显示图
show(graph);
destroyGraph(graph);
system("pause");
/*while (1);*/
return 0;
}
Graph* createGraph()
{
//结构
Graph* graph = new Graph;//先把结构开起来
//内容
graph->edges = graph->vertexs = 0;
graph->ppEdge = NULL;
graph->pVertex = NULL;
//一行代码搞定
//memset(graph, 0, sizeof(Graph));
return graph;
}
void initGraph(Graph* graph,int vertexs,int lines, char* str, int map[VERTEXS][VERTEXS]){
//这里是重载,不需要输入,直接初始化
graph->vertexs = VERTEXS;
graph->edges = lines;
//开内存
graph->pVertex = new char[graph->vertexs + 1];//保存顶点的一位数组
//保存描述边的二维数组
graph->ppEdge = new int*[graph->vertexs];
for (int i = 0; i < graph->vertexs; i++)
{
graph->ppEdge[i] = new int[graph->vertexs];
memset(graph->ppEdge[i], 0, sizeof(int)*graph->vertexs);
}
//表示从str里向前面的顶点集复制6个字符
memcpy(graph->pVertex, str, 6);
for (int i = 0; i < vertexs; i++){
for (int j = 0; j < vertexs; j++){//这里竟然写成了i++
graph->ppEdge[i][j] = map[i][j];
}
}
}
void initGraph(Graph* graph)
{
cout << "输入顶点个数" << endl;
cin >> graph->vertexs;
cout << "输入边的个数" << endl;
cin >> graph->edges;
//开内存
graph->pVertex = new char[graph->vertexs+1];//保存顶点的一位数组
//保存描述边的二维数组
graph->ppEdge = new int*[graph->vertexs];
for (int i = 0; i < graph->vertexs; i++)
{
graph->ppEdge[i] = new int[graph->vertexs];
memset(graph->ppEdge[i], 0, sizeof(int)*graph->vertexs);
}
//赋值
cout << "请输入顶点:" << endl;
scanf("%s", graph->pVertex);//自己写就这样写,给别人用,就写循环
//对于一段内存的输入,都是找到首地址
/*while (cin >> graph->pVertex)
{
}*/
char buff[5] = { 0 };
int srcIdx, dstIdx;
for (int i = 0; i < graph->edges; i++)
{
cout << "请输入第" << i + 1 << "条边(A->B):" ;
scanf("%s", buff);
srcIdx = _getIndex(graph, buff[0]);
dstIdx = _getIndex(graph, buff[3]);
graph->ppEdge[srcIdx][dstIdx] = 1;
//如果加了无向图
//#if WUXIANG
graph->ppEdge[dstIdx][srcIdx] = 1;
//#endif
}
}
//返回顶点在图中下标,如果没有这个顶点,就返回-1
int _getIndex(Graph* graph, char c)
{
for (int i = 0; i < graph->vertexs; i++)
{
if (c == graph->pVertex[i]) return i;
}
return -1;
}
//打印图
void show(Graph* graph)
{
for (int i = 0; i <= graph->vertexs; i++){
for (int j = 0; j <= graph->vertexs; j++){
if (i == 0 && j == 0)//左上角空置
cout << " ";
else if (i == 0){
printf("%c ", graph->pVertex[j - 1]);
}
else if (j == 0){
printf("%c ", graph->pVertex[i - 1]);
}
else{
printf("%d ", graph->ppEdge[i - 1][j - 1]);
}
}
printf("\n");
}
}
void destroyGraph(Graph * graph)
{
}
//#include<iostream>
//#include<vector>
//using namespace std;
//#define N 10005
//int n, m, ans;
//vector<int> mp[N];
//void dfs(int last, int x, int num) //因为只有四个点,而第一个和最后一个点可以相同,所以只要保证每个点和它上上个点不同即可(它和上个点一定不同,因为存在一条边)
//{
// if (num == 3)
// {
// ans++; return;
// }
// for (int i = 0; i<mp[x].size(); i++)
// {
// if (mp[x][i] != last)
// {
// dfs(x, mp[x][i], num + 1);
// }
// }
//}
//int main()
//{
// scanf("%d%d", &n, &m);
// for (int i = 0; i<m; i++)
// {
// int u, v;
// scanf("%d%d", &u, &v);
// mp[u].push_back(v);
// mp[v].push_back(u);
// }
// for (int i = 1; i <= n; i++)
// {
// dfs(-1, i, 0);
// }
// cout << ans << endl;
// return 0;
//}