补充未提交的实验代码
This commit is contained in:
126
datastructure/2025301205+施光甲+实验七.cpp
Normal file
126
datastructure/2025301205+施光甲+实验七.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#include<stdio.h>
|
||||
|
||||
int inf = 1000;
|
||||
|
||||
typedef struct{
|
||||
int weight; //结点权值
|
||||
int parent,lchild,rchild; //结点的双亲、左孩子、右孩子的下标
|
||||
char ch; //字符
|
||||
}HTNode,*HuffmanTree;
|
||||
|
||||
//查找
|
||||
int Find(HuffmanTree HT, int n)
|
||||
{
|
||||
int min = 0;
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
if (HT[i].weight<HT[min].weight && HT[i].parent == 0)
|
||||
min = i;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
//选择
|
||||
void select(HuffmanTree HT, int n, int &s1, int &s2) //传入参数n=k-1
|
||||
{
|
||||
s1 = Find(HT, n); //a、在HT[k](1≤k≤i-1)中选择两个其双亲域为0, 且权值最小的结点,并返回它们在HT中的序号s1和s2
|
||||
HT[s1].parent = n + 1; //b、得到新结点n + 1,从森林中删除s1,s2,将s1,s2的双亲域由0改为k (即n+1)
|
||||
s2 = Find(HT, n);
|
||||
HT[s2].parent = n + 1; //b、得到新结点n + 1,从森林中删除s1,s2,将s1,s2的双亲域由0改为k (即n+1)
|
||||
}
|
||||
|
||||
//构造
|
||||
void CreatHuffmanTree (HuffmanTree &HT, int weight[], char c[], int n) //char c[100]; 字母
|
||||
{
|
||||
if(n<=1) return;
|
||||
int m = 2 * n - 1; //数组存储2n-1个元素
|
||||
HT=new HTNode[m+1]; //0号单元未用,所以需要开辟m+1个单元,HT[m]表示根结点
|
||||
for (int i = 1; i <= m; ++i) //将2n-1个元素的lch、 rch、 parent初始化为0, ch字符全部初始化为#
|
||||
{
|
||||
//todo list 处理parent 、lchild 、rchild
|
||||
HT[i].parent = 0;
|
||||
HT[i].lchild = 0;
|
||||
HT[i].rchild = 0;
|
||||
HT[i].ch = '#';
|
||||
}
|
||||
HT[0].weight = inf; //int inf = 1000;
|
||||
|
||||
for (int j = 1; j <= n; ++j)
|
||||
{
|
||||
//todo list //获取 前n个单元中叶子节点的 weight值
|
||||
HT[j].weight = weight[j];
|
||||
HT[j].ch = c[j]; //获取 前n个单元中叶子节点的 字符
|
||||
}
|
||||
for (int k = n + 1; k <= m; ++k) //合并产生n-1个结点——构造Huffman树
|
||||
{
|
||||
int s1, s2;
|
||||
select(HT, k - 1, s1, s2); //选择两个需要求和的下标
|
||||
//todo list //c、s1,s2分别作为k的左右孩子
|
||||
HT[k].lchild = s1;
|
||||
HT[k].rchild = s2;
|
||||
//todo list //c、k 的权值为左右孩子权值之和
|
||||
HT[k].weight = HT[s1].weight + HT[s2].weight;
|
||||
}
|
||||
}
|
||||
|
||||
//输出哈夫曼树
|
||||
void DisplayHF(HuffmanTree HT, int r)
|
||||
{
|
||||
printf("%c %d\n",HT[r].ch,HT[r].weight);
|
||||
|
||||
int s1 = HT[r].lchild;
|
||||
int s2 = HT[r].rchild;
|
||||
if (s1 != 0)
|
||||
DisplayHF(HT, s1);
|
||||
if (s2 != 0)
|
||||
DisplayHF(HT, s2);
|
||||
}
|
||||
|
||||
//输出哈夫曼编码
|
||||
void DisplayHFCode(HuffmanTree HT, int r,int arr[], int top)
|
||||
{
|
||||
int s1 = HT[r].lchild; // 获取当前节点的左孩子索引赋值给s1
|
||||
int s2 = HT[r].rchild; // 获取当前节点的右孩子索引赋值给s2
|
||||
|
||||
if (HT[r].lchild != 0) { //左孩子存在
|
||||
arr[top] = 0; // 在路径数组arr的当前位置top存入0,表示走向左孩子
|
||||
DisplayHFCode(HT, s1, arr, top + 1); // 递归调用DisplayHFCode函数,处理左孩子节点,同时top加1
|
||||
}
|
||||
if (HT[r].rchild != 0) { //右孩子存在
|
||||
arr[top] = 1; // 在路径数组arr的当前位置top存入1,表示走向右孩子
|
||||
DisplayHFCode(HT, s2, arr, top + 1); // 递归调用DisplayHFCode函数,处理右孩子节点,同时top加1
|
||||
}
|
||||
if (HT[r].lchild==0 && HT[r].rchild==0) { //叶子节点
|
||||
printf("字符 %c 的编码: ", HT[r].ch); // 打印当前叶子节点对应的字符
|
||||
for (int i = 0; i < top; ++i) { // 遍历路径数组arr,从0到top-1
|
||||
printf("%d", arr[i]); // 打印路径数组中的每个元素,即字符的哈夫曼编码
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
HuffmanTree HT;
|
||||
int a[100]; //权值
|
||||
char c[100]; //字母
|
||||
int arr[100]; //arr:用于存储从根结点到当前结点的路径上的0和1的数组
|
||||
int top = 0; //top: arr数组的当前索引,表示已经存储到的路径的长度
|
||||
|
||||
printf("请输入七组数据!(字母 权值)\n");
|
||||
for (int i = 1; i <= 7; i++) {
|
||||
scanf("%c %d",&c[i],&a[i]);
|
||||
getchar();
|
||||
}
|
||||
CreatHuffmanTree (HT, a, c, 7);
|
||||
printf("哈夫曼树先序遍历序列为(字母 权值):\n");
|
||||
printf("新生成结点用‘#’标记\n");
|
||||
DisplayHF(HT, 7 * 2 - 1);
|
||||
|
||||
printf("哈夫曼编码为:\n");
|
||||
DisplayHFCode(HT,7 * 2 - 1, arr, top);
|
||||
|
||||
// 释放动态分配的内存(补充内存释放,避免内存泄漏,不影响原有逻辑)
|
||||
delete[] HT;
|
||||
return 0;
|
||||
}
|
||||
@@ -4,195 +4,301 @@
|
||||
typedef int Status;
|
||||
typedef struct BiTNode
|
||||
{
|
||||
char data; //结点数据域
|
||||
struct BiTNode *lchild, *rchild; //左右孩子指针
|
||||
}BiTNode,*BiTree;
|
||||
char data; // 结点数据域
|
||||
struct BiTNode *lchild, *rchild; // 左右孩子指针
|
||||
} BiTNode, *BiTree;
|
||||
|
||||
//1、创建二叉链表:按先序次序输入二叉树中结点的值,创建二叉链表表示的二叉树T
|
||||
// 例:建立课本P115图5.10(b)的二叉树--读入字符的顺序为:ABC##DE#G##F###(#表示空树)
|
||||
// 1、创建二叉链表:按先序次序输入二叉树中结点的值,创建二叉链表表示的二叉树T
|
||||
// 例:建立课本P115图5.10(b)的二叉树——读入字符的顺序为:ABC##DE#G##F###(#表示空树)
|
||||
BiTree Create(BiTree &T)
|
||||
{
|
||||
char ch;
|
||||
printf("请输入一个字符:");
|
||||
scanf("%c",&ch);
|
||||
getchar(); //清空缓冲区,把遗留的\n清除
|
||||
//todo list //if: 如果输入的是'#',则建立一棵空树
|
||||
//else:否则,递归建立一个二叉树(注意:是按按先序次序创建的二叉树)
|
||||
if(ch == '#') {
|
||||
T = NULL; //建立空树
|
||||
} else {
|
||||
T = (BiTree)malloc(sizeof(BiTNode)); //创建新结点
|
||||
T->data = ch;
|
||||
T->lchild = NULL;
|
||||
T->rchild = NULL;
|
||||
T->lchild = Create(T->lchild); //递归创建左子树
|
||||
T->rchild = Create(T->rchild); //递归创建右子树
|
||||
}
|
||||
return T;
|
||||
char ch;
|
||||
printf("请输入一个字符:");
|
||||
scanf("%c", &ch);
|
||||
getchar(); // 清空缓冲区,把遗留的\n清除
|
||||
|
||||
// todo list //if: 如果输入的是’#’,则建立一棵空树
|
||||
if (ch == '#')
|
||||
{
|
||||
T = NULL;
|
||||
}
|
||||
// else:否则,递归建立一个二叉树(注意:是按按先序次序创建的二叉树)
|
||||
else
|
||||
{
|
||||
T = (BiTree)malloc(sizeof(BiTNode));
|
||||
T->data = ch;
|
||||
Create(T->lchild);
|
||||
Create(T->rchild);
|
||||
}
|
||||
return T;
|
||||
}
|
||||
|
||||
//先序遍历二叉树
|
||||
Status PreOrder(BiTree &T)
|
||||
// 先序遍历二叉树
|
||||
Status PreOrder(BiTree &T)
|
||||
{
|
||||
//todo list //if: 如果是空树,则返回
|
||||
//else:否则,先访问根结点 (D)
|
||||
//前序遍历左子树 (L)
|
||||
//前序遍历右子树 (R)
|
||||
if(T == NULL) {
|
||||
return OK;
|
||||
} else {
|
||||
printf("%c ", T->data); //访问根结点
|
||||
PreOrder(T->lchild); //前序遍历左子树
|
||||
PreOrder(T->rchild); //前序遍历右子树
|
||||
}
|
||||
return OK;
|
||||
// todo list //if: 如果是空树,则返回
|
||||
if (T == NULL)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
// else:否则,先访问根结点 (D)
|
||||
else
|
||||
{
|
||||
printf("%c ", T->data);
|
||||
// 前序遍历左子树 (L)
|
||||
PreOrder(T->lchild);
|
||||
// 前序遍历右子树 (R)
|
||||
PreOrder(T->rchild);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
//中序遍历二叉树
|
||||
// 中序遍历二叉树
|
||||
Status InOrder(BiTree &T)
|
||||
{
|
||||
//todo list //if: 如果是空树,则返回
|
||||
//else:否则,先中序遍历左子树 (L)
|
||||
//访问根结点 (D)
|
||||
//中序遍历右子树 (R)
|
||||
if(T == NULL) {
|
||||
return OK;
|
||||
} else {
|
||||
InOrder(T->lchild); //中序遍历左子树
|
||||
printf("%c ", T->data); //访问根结点
|
||||
InOrder(T->rchild); //中序遍历右子树
|
||||
}
|
||||
return OK;
|
||||
// todo list //if: 如果是空树,则返回
|
||||
if (T == NULL)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
// else:否则,先中序遍历左子树 (L)
|
||||
else
|
||||
{
|
||||
InOrder(T->lchild);
|
||||
// 访问根结点 (D)
|
||||
printf("%c ", T->data);
|
||||
// 中序遍历右子树 (R)
|
||||
InOrder(T->rchild);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
//后序遍历
|
||||
// 后序遍历
|
||||
Status PostOrder(BiTree &T)
|
||||
{
|
||||
//todo list //if: 如果是空树,则返回
|
||||
//else:否则,先后序遍历左子树 (L)
|
||||
//后序遍历右子树 (R)
|
||||
//访问根结点 (D)
|
||||
if(T == NULL) {
|
||||
return OK;
|
||||
} else {
|
||||
PostOrder(T->lchild); //后序遍历左子树
|
||||
PostOrder(T->rchild); //后序遍历右子树
|
||||
printf("%c ", T->data); //访问根结点
|
||||
}
|
||||
return OK;
|
||||
// todo list //if: 如果是空树,则返回
|
||||
if (T == NULL)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
// else:否则,先后序遍历左子树 (L)
|
||||
else
|
||||
{
|
||||
PostOrder(T->lchild);
|
||||
// 后序遍历右子树 (R)
|
||||
PostOrder(T->rchild);
|
||||
// 访问根结点 (D)
|
||||
printf("%c ", T->data);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
//层次遍历1
|
||||
// 层次遍历1
|
||||
void LeverOrder(BiTree &T)
|
||||
{
|
||||
if (T == NULL) { // 处理空树,避免空指针访问
|
||||
if (T == NULL)
|
||||
{ // 处理空树,避免空指针访问
|
||||
printf("二叉树为空!\n");
|
||||
return;
|
||||
}
|
||||
//BT *Queue[100]; //队列
|
||||
BiTree Queue[100]; //队列
|
||||
char ch;
|
||||
int front = 0;
|
||||
int rear = 0;
|
||||
// 队列边界检查(新增:防止数组越界)
|
||||
if (rear >= 100) {
|
||||
// BT *Queue[100]; //队列
|
||||
BiTree Queue[100]; // 队列
|
||||
char ch;
|
||||
int front = 0;
|
||||
int rear = 0;
|
||||
// 队列边界检查(新增:防止数组越界)
|
||||
if (rear >= 100)
|
||||
{
|
||||
printf("队列已满,无法入队!\n");
|
||||
return;
|
||||
}
|
||||
Queue[rear++] = T; //根节点入队
|
||||
while (front < rear) //当队不空
|
||||
{
|
||||
ch = Queue[front]->data; //出队队头元素
|
||||
printf("%c ",ch);
|
||||
if (Queue[front]->lchild){
|
||||
if (rear >= 100) {
|
||||
printf("队列已满,左孩子无法入队!\n");
|
||||
Queue[rear++] = T; // 根节点入队
|
||||
while (front < rear) // 当队不空
|
||||
{
|
||||
ch = Queue[front]->data; // 出队队头元素
|
||||
printf("%c ", ch);
|
||||
if (Queue[front]->lchild)
|
||||
{
|
||||
if (rear >= 100)
|
||||
{
|
||||
printf("队列已满,左孩子无法入队!\n");
|
||||
break;
|
||||
}
|
||||
Queue[rear++] = Queue[front]->lchild;
|
||||
}
|
||||
if (Queue[front]->rchild){
|
||||
if (rear >= 100) {
|
||||
printf("队列已满,右孩子无法入队!\n");
|
||||
break;
|
||||
}
|
||||
Queue[rear++] = Queue[front]->rchild;
|
||||
}
|
||||
front++; // 队头后移,完成出队
|
||||
}
|
||||
|
||||
Queue[rear++] = Queue[front]->lchild;
|
||||
}
|
||||
if (Queue[front]->rchild)
|
||||
{
|
||||
if (rear >= 100)
|
||||
{
|
||||
printf("队列已满,右孩子无法入队!\n");
|
||||
break;
|
||||
}
|
||||
Queue[rear++] = Queue[front]->rchild;
|
||||
}
|
||||
front++; // 队头后移,完成出队
|
||||
}
|
||||
}
|
||||
|
||||
//节点总数
|
||||
/*
|
||||
|
||||
// ------------- 循环队列结构体定义(层序遍历依赖队列) -------------
|
||||
#define MAXQSIZE 100 // 队列最大容量
|
||||
typedef struct {
|
||||
BiTree base[MAXQSIZE]; // 队列存储二叉树结点指针
|
||||
int front; // 队头指针
|
||||
int rear; // 队尾指针
|
||||
} SqQueue;
|
||||
|
||||
// 初始化队列
|
||||
int InitQueue(SqQueue *qu) {
|
||||
qu->front = qu->rear = 0; // 空队列:队头=队尾=0
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 判断队列是否为空
|
||||
int QueueEmpty(SqQueue *qu) {
|
||||
return qu->front == qu->rear;
|
||||
}
|
||||
|
||||
// 入队操作(将二叉树结点指针入队)
|
||||
int enQueue(SqQueue *qu, BiTree p) {
|
||||
// 判断队列是否满(循环队列判满条件)
|
||||
if ((qu->rear + 1) % MAXQSIZE == qu->front) {
|
||||
printf("队列满,入队失败!\n");
|
||||
return 0;
|
||||
}
|
||||
qu->base[qu->rear] = p; // 结点指针入队
|
||||
qu->rear = (qu->rear + 1) % MAXQSIZE; // 队尾指针后移
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 出队操作(取出队头结点指针)
|
||||
int deQueue(SqQueue *qu, BiTree *p) {
|
||||
if (QueueEmpty(qu)) { // 队空则出队失败
|
||||
printf("队列空,出队失败!\n");
|
||||
return 0;
|
||||
}
|
||||
*p = qu->base[qu->front]; // 取出队头元素
|
||||
qu->front = (qu->front + 1) % MAXQSIZE; // 队头指针后移
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ------------- 层次遍历2 -------------
|
||||
void LevelOrder(BiTree b) {
|
||||
BiTree p;
|
||||
SqQueue qu; // 定义队列(注意:原参考中qu是指针,此处改为直接定义结构体,更易理解)
|
||||
|
||||
if (b == NULL) return; // 空树直接返回
|
||||
|
||||
InitQueue(&qu); // 初始化队列
|
||||
enQueue(&qu, b); // 根结点入队
|
||||
|
||||
while (!QueueEmpty(&qu)) { // 队列非空则循环
|
||||
deQueue(&qu, &p); // 出队当前结点
|
||||
printf("%c ", p->data); // 访问当前结点
|
||||
|
||||
// 左孩子非空则入队
|
||||
if (p->lchild != NULL) {
|
||||
enQueue(&qu, p->lchild);
|
||||
}
|
||||
// 右孩子非空则入队
|
||||
if (p->rchild != NULL) {
|
||||
enQueue(&qu, p->rchild);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// 节点总数
|
||||
int Count(BiTree &T)
|
||||
{
|
||||
//todo list //if:如果是空树,则结点个数为0;
|
||||
//else:否则,结点个数为左子树的结点个数+右子树的结点个数再+1。
|
||||
if(T == NULL) {
|
||||
return 0;
|
||||
} else {
|
||||
return Count(T->lchild) + Count(T->rchild) + 1;
|
||||
}
|
||||
// todo list //if:如果是空树,则结点个数为0;
|
||||
if (T == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// else:否则,结点个数为左子树的结点个数+右子树的结点个数再+1。
|
||||
else
|
||||
{
|
||||
return Count(T->lchild) + Count(T->rchild) + 1;
|
||||
}
|
||||
}
|
||||
//叶子节点
|
||||
// 叶子节点
|
||||
int CountLeaf(BiTree &T)
|
||||
{
|
||||
//todo list //if:如果是空树,则叶子结点个数为0;
|
||||
//else if:如果是叶子结点,则返回1;
|
||||
//else否则,为左子树的叶子结点个数+右子树的叶子结点个数。
|
||||
if(T == NULL) {
|
||||
return 0;
|
||||
} else if(T->lchild == NULL && T->rchild == NULL) {
|
||||
return 1;
|
||||
} else {
|
||||
return CountLeaf(T->lchild) + CountLeaf(T->rchild);
|
||||
}
|
||||
// todo list //if:如果是空树,则叶子结点个数为0;
|
||||
if (T == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// else if:如果是叶子结点,则返回1;
|
||||
else if (T->lchild == NULL && T->rchild == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
// else否则,为左子树的叶子结点个数+右子树的叶子结点个数。
|
||||
else
|
||||
{
|
||||
return CountLeaf(T->lchild) + CountLeaf(T->rchild);
|
||||
}
|
||||
}
|
||||
int main()
|
||||
{
|
||||
BiTree T = NULL; //创建一颗空树
|
||||
int choose = -1;
|
||||
printf("*********************************************\n");
|
||||
printf("********** 实验六 *******\n");
|
||||
printf("*********************************************\n");
|
||||
printf("********** 1.创建一棵二叉树 *******\n");
|
||||
printf("********** 2.先序遍历二叉树 *******\n");
|
||||
printf("********** 3.中序遍历二叉树 *******\n");
|
||||
printf("********** 4.后序遍历二叉树 *******\n");
|
||||
printf("********** 5.层序遍历二叉树 *******\n");
|
||||
printf("********** 6.求二叉树节点个数 *******\n");
|
||||
printf("********** 7.求二叉数叶子节点个数 *******\n");
|
||||
printf("********** 0.退出 *******\n");
|
||||
printf("*********************************************\n");
|
||||
while (choose)
|
||||
{
|
||||
printf("\n");
|
||||
printf("请输入你的选择项:");
|
||||
scanf("%d", &choose);
|
||||
getchar(); //清空缓冲区,把遗留的\n清除
|
||||
switch (choose)
|
||||
{
|
||||
case 1:T = Create(T); break; //创建
|
||||
printf("\n");
|
||||
case 2:
|
||||
printf("先序序列为:") ;
|
||||
PreOrder(T); break; //先序遍历二叉树
|
||||
printf("\n");
|
||||
case 3:
|
||||
printf("中序序列为:") ;
|
||||
InOrder(T); break; //中序遍历二叉树
|
||||
printf("\n");
|
||||
case 4:
|
||||
printf("后序序列为:") ;
|
||||
PostOrder(T); break; //后序遍历二叉树
|
||||
printf("\n");
|
||||
case 5:
|
||||
printf("层次序列为:") ;
|
||||
LeverOrder(T); break; //层序遍历二叉树
|
||||
printf("\n");
|
||||
case 6:printf("节点总数为:%d\n", Count(T)); break;//结点总数
|
||||
case 7:printf("叶子节点总数为:%d\n", CountLeaf(T)); break; //叶子结点总数
|
||||
case 0:exit(0); break;
|
||||
}
|
||||
}
|
||||
BiTree T = NULL; // 创建一颗空树
|
||||
int choose = -1;
|
||||
printf("*********************************************\n");
|
||||
printf("********** 实验六 *******\n");
|
||||
printf("*********************************************\n");
|
||||
printf("********** 1.创建一棵二叉树 *******\n");
|
||||
printf("********** 2.先序遍历二叉树 *******\n");
|
||||
printf("********** 3.中序遍历二叉树 *******\n");
|
||||
printf("********** 4.后序遍历二叉树 *******\n");
|
||||
printf("********** 5.层序遍历二叉树 *******\n");
|
||||
printf("********** 6.求二叉树节点个数 *******\n");
|
||||
printf("********** 7.求二叉数叶子节点个数 *******\n");
|
||||
printf("********** 0.退出 *******\n");
|
||||
printf("*********************************************\n");
|
||||
while (choose)
|
||||
{
|
||||
printf("\n");
|
||||
printf("请输入你的选择项:");
|
||||
scanf("%d", &choose);
|
||||
getchar(); // 清空缓冲区,把遗留的\n清除
|
||||
switch (choose)
|
||||
{
|
||||
case 1:
|
||||
T = Create(T);
|
||||
break; // 创建
|
||||
printf("\n");
|
||||
case 2:
|
||||
printf("先序序列为:");
|
||||
PreOrder(T);
|
||||
break; // 先序遍历二叉树
|
||||
printf("\n");
|
||||
case 3:
|
||||
printf("中序序列为:");
|
||||
InOrder(T);
|
||||
break; // 中序遍历二叉树
|
||||
printf("\n");
|
||||
case 4:
|
||||
printf("后序序列为:");
|
||||
PostOrder(T);
|
||||
break; // 后序遍历二叉树
|
||||
printf("\n");
|
||||
case 5:
|
||||
printf("层次序列为:");
|
||||
LeverOrder(T);
|
||||
break; // 层序遍历二叉树
|
||||
printf("\n");
|
||||
case 6:
|
||||
printf("节点总数为:%d\n", Count(T));
|
||||
break; // 结点总数
|
||||
case 7:
|
||||
printf("叶子节点总数为:%d\n", CountLeaf(T));
|
||||
break; // 叶子结点总数
|
||||
case 0:
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
180
datastructure/2025301205+施光甲+试验八.cpp
Normal file
180
datastructure/2025301205+施光甲+试验八.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MaxSize 8
|
||||
|
||||
typedef struct ArcNode { //【边结点】
|
||||
int adjvex; //该边所指向的顶点的位置
|
||||
struct ArcNode* nextarc; //指向下一条边的指针
|
||||
}ArcNode;
|
||||
|
||||
typedef struct VNode { //【表头结点】
|
||||
char data[3]; //顶点信息--每个顶点的数据是一个由3个字符组成的字符串(或字符数组)V0,V1
|
||||
ArcNode* firstarc; //指向第一条依附该顶点的边的指针
|
||||
}VNode;
|
||||
|
||||
typedef struct {
|
||||
VNode vertices[MaxSize]; //邻接表(vertices为数组名)
|
||||
int vexnum, arcnum; //图的当前顶点数和边数
|
||||
}ALGragh;
|
||||
|
||||
|
||||
//1、构建图:参考P151算法6.2
|
||||
void InitList(ALGragh &G, char a[][3]) {
|
||||
int i, j;
|
||||
for (i = 0; i < G.vexnum; i++) {
|
||||
for (j = 0; j < 3; j++)
|
||||
G.vertices[i].data[j] = a[i][j]; //todo list //输入顶点值
|
||||
G.vertices[i].firstarc = NULL; //todo list //初始化表头结点的指针域为NULL
|
||||
}
|
||||
|
||||
printf("请输入各边所依附的两个顶点的位置\n");
|
||||
for (int k = 0; k < G.arcnum; k++) {
|
||||
scanf("%d %d", &i, &j);
|
||||
//生成一个新的边结点*p1:
|
||||
ArcNode* p1 = (ArcNode*)malloc(sizeof(struct ArcNode));
|
||||
p1->adjvex = j;
|
||||
p1->nextarc = G.vertices[i].firstarc;
|
||||
G.vertices[i].firstarc = p1; //todo list 设此邻接点序号为j,并将新结点*p1插入顶点vi的边表头部(头插法)
|
||||
|
||||
//生成另一个对称的新的边结点*p2:
|
||||
ArcNode* p2 = (ArcNode*)malloc(sizeof(struct ArcNode));
|
||||
p2->adjvex = i;
|
||||
p2->nextarc = G.vertices[j].firstarc;
|
||||
G.vertices[j].firstarc = p2; //todo list 设此邻接点序号为i,并将新结点*p2插入顶点vj的边表头部(头插法)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//2、输出邻接表
|
||||
void PrintInf(ALGragh G) {
|
||||
int i;
|
||||
ArcNode* p; //struct ArcNode* p;
|
||||
printf("输出图的邻接表:\n");
|
||||
for (i = 0; i < G.vexnum; i++) { //G.vexnum表示图中的顶点数量。
|
||||
printf("%s ", G.vertices[i].data); //打印当前顶点 i 的数据 (%s 被用于表示待插入的数据是字符串类型)
|
||||
for (p = G.vertices[i].firstarc; p != NULL; p = p->nextarc) //for循环遍历当前顶点 i 的所有邻接顶点,并打印这些邻接顶点。
|
||||
printf("%d ", p->adjvex);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//3、对采用【邻接表】表示的图,做深度优先遍历:参考P157算法6.6
|
||||
void DFS_AL(ALGragh G, int visited[], int v) {
|
||||
printf("%s ", G.vertices[v].data); // 访问第 v 个顶点
|
||||
ArcNode* p;
|
||||
int w;
|
||||
visited[v] = 1;
|
||||
|
||||
p = G.vertices[v].firstarc; //todo list //将 p 初始化为指向顶点 v 的第一个邻接点的指针
|
||||
while (p != NULL) { //todo list //while循环:对v未被访问的邻接顶点w递归调用DFSTraverse 函数;并寻找v相对于w的下一个邻接点
|
||||
w = p->adjvex;
|
||||
if (!visited[w]) {
|
||||
DFS_AL(G, visited, w);
|
||||
}
|
||||
p = p->nextarc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//4、深度优先遍历非连通图(也兼容连通图) : 参考P156算法6.4 (可用于计算连通分量的个数,但需要增加count变量,如下算法5)
|
||||
void DFSTraverse_AL(ALGragh G, int visited[]) {
|
||||
int v;
|
||||
for (v = 0; v < G.vexnum; v++) //初始化标记数组,置为0
|
||||
visited[v] = 0;
|
||||
for (v = 0; v < G.vexnum; v++)
|
||||
if (!visited[v]) { //todo list 如果有顶点没有被访问,那就以它为起点遍历所在的连通分量
|
||||
DFS_AL(G, visited, v);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//5、计算连通分量的个数
|
||||
void Count(ALGragh G, int visited[]) {
|
||||
int count = 0, v;
|
||||
for (v = 0; v < G.vexnum; v++) //初始化标记数组,置为0
|
||||
visited[v] = 0;
|
||||
for (v = 0; v < G.vexnum; v++)
|
||||
if (!visited[v]) { //todo list 如果有顶点没有被访问,那就以它为起点遍历所在的连通分量,连通分量个数加一
|
||||
DFS_AL(G, visited, v);
|
||||
count++;
|
||||
}
|
||||
printf("\n");
|
||||
printf("连通分量个数:%d\n", count);
|
||||
}
|
||||
|
||||
|
||||
//6、判断有无路径可达
|
||||
void Judge(ALGragh G, int visited[], int v, int u) {
|
||||
for (int i = 0; i < G.vexnum; i++)
|
||||
visited[i] = 0;
|
||||
DFS_AL(G, visited, v); //todo list 以v作为起点,做深度优先遍历图,在此过程中不断将所有相互连接的邻接结点的visited[u]更新为1
|
||||
if (visited[u] == 1){
|
||||
printf("\n");
|
||||
printf("V%d与V%d有路径可达!\n", v, u);
|
||||
}
|
||||
else{
|
||||
printf("\n");
|
||||
printf("V%d与V%d无路径可达!\n", v, u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main() {
|
||||
int v, u; //j是边的数目,v、u为顶点位置
|
||||
int choose = -1;
|
||||
//a是一个二维字符数组,存储顶点信息(字符串还得保存结尾的空字符\0,因此列数需要设为3)
|
||||
char a[MaxSize][3] = { "V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7" };
|
||||
int visited[MaxSize] = { 0 };
|
||||
ALGragh G;
|
||||
G.vexnum = MaxSize;
|
||||
|
||||
printf("*****************************************************\n");
|
||||
printf("********** 实验八 *******\n");
|
||||
printf("*****************************************************\n");
|
||||
printf("********** 1.构建图 *******\n");
|
||||
printf("********** 2.输出邻接表 *******\n");
|
||||
printf("********** 3.深度优先遍历的结果 *******\n");
|
||||
printf("********** 4.判断两个点之间是否有路径可达 *******\n");
|
||||
printf("********** 5.输出连通分量的个数 *******\n");
|
||||
printf("********** 0.退出 *******\n");
|
||||
printf("*****************************************************\n");
|
||||
while(choose) {
|
||||
printf("请输入你的选择项:");
|
||||
scanf("%d", &choose);
|
||||
switch(choose){
|
||||
case 1:
|
||||
printf("输入边数:");
|
||||
scanf("%d", &G.arcnum);
|
||||
InitList(G, a);
|
||||
break;
|
||||
case 2:
|
||||
PrintInf(G);
|
||||
break;
|
||||
case 3:
|
||||
printf("深度优先遍历结果:");
|
||||
DFSTraverse_AL(G, visited); // 3 深度优先遍历图
|
||||
//DFS_AL(G, visited,v); //如果是一个连通图,直接调用 DFS_AL也可以得到正确结果
|
||||
printf("\n");
|
||||
break;
|
||||
case 4:
|
||||
printf("输入要判断的两个点:");
|
||||
scanf("%d %d", &v, &u);
|
||||
Judge(G, visited, v, u);
|
||||
break;
|
||||
case 5:
|
||||
Count(G, visited);
|
||||
break;
|
||||
case 0:
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user