数据结构 派

今天 我决定开启我的数据结构之路,话说虽然我学的是电子信息类,但是其实也要用到计算机,哎 老师说数据结构是计算机专业的核心课程 好吧 我今天就开始啃这个硬核,项目先不做。先注重把这些基础夯实就行了。

其实真的在学习之前,想一下你为啥要学这个,是闲的蛋疼吗,我相信肯定知道学这个好,有用处,你才来学,那好在哪里,你有清楚吗。很多人慌着去赶紧开始正文,其实真的欲速则不达,你都没有弄清初心,后面一定会出问题的。而且也不是,模糊的知道好 反正就是好,好个屁,你的大脑会说,反正我不知道 是咋好,你爱咋咋。在三分钟热度过后,自然凉凉。

为啥要学习数据结构和算法
数据结构代表一种批量存储数据的方式,强调的是逻辑思维

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;
//}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值