链表二叉树图的基础C语言

1. 链表

实现二次多项式加法

#include<stdio.h>
#include<stdlib.h>

typedef struct Poly{ // 定义为二次多项式
    double a;
    double b;
    double c;
}POLY;

typedef struct Lnode{
    POLY p;
    struct Lnode *next;
}LNODE, *LinkList;




int InitList(LinkList &L) // 初始化单链表
{
	L = (LNODE*)malloc(sizeof(LNODE));//分配一个头节点
	if (L == NULL)
		return false;//内存不足,分配失败
	L->next = NULL;//头节点之后还没有节点
		return true;
}

void Insert(LinkList &L) // 单链表插入新的值(使用的是头插)
{
	
    double a, b, c;
    LNODE *p = L;
    LNODE *s = (LNODE*)malloc(sizeof(LNODE));//申请空间给新的节点s
    
    	printf("多项式为: a * x^2 + b * x + c 请分别输入a, b, c的值:\n");
        scanf("%lf %lf %lf", &a, &b, &c);
        s->p.a = a;
        s->p.b = b;
        s->p.c = c;
    s->next = p->next;//改变插入节点的指针域
    p->next = s;//使头节点的指针域指向插入的节点

}

void PrintList(LinkList &L)//打印单链表
{
	LNODE *p=L;//创建一个p指针指向头节点
	printf("表中的元素为:\n");
	while (p->next!=NULL)//判断下一个节点是不是空指针,也可以简写为p->next
	{
		p = p->next;
		printf("结点:\n");
		printf("%.2lf ", p->p.a);
		printf("%.2lf ", p->p.b);
		printf("%.2lf ", p->p.c);
		printf("\n");
	}
	printf("\n");
}


void PolyAdd(LinkList &L)
{
	printf("多项式相加结果如下:\n"); 
	LNODE *po = L->next;
	LNODE *s = (LNODE*)malloc(sizeof(LNODE));
	s = po->next;
	
	double a[3] = {0};
	a[0] = po->p.c + s->p.c;
	a[1] = po->p.b + s->p.b;
	a[2] = po->p.a + s->p.a;
	printf("高到低 a: %.2lf b: %.2lf c: %.2lf \n", a[2], a[1], a[0]);
	printf("低到高 c: %.2lf b: %.2lf a: %.2lf ", a[0], a[1], a[2]);
	
}


int main()
{
    LinkList L;//声明一个指向单链表的指针,此时并没有创建一个节点
    InitList(L);//初始化一个空表
    printf("请输入你想插入几个值: \n");
    int num = 0;
    scanf("%d", &num);
    for(int i = 0; i < num; i++)
    {
        Insert(L);
    }
    PrintList(L);
    
    PolyAdd(L);
    
    return 0;
}

运行截图如下:
在这里插入图片描述

2.二叉树

二叉树层序生成及先序中序后序遍历

#include<stdio.h>
#include<stdlib.h>
#define BLANK -1 
#define LEFT -2
#define RIGHT -3
typedef struct BINARY_TREE
{
	// 左子树
	struct BINARY_TREE *left;
	// 右子树
	struct BINARY_TREE *right;
	int value;
} Binary_tree;

typedef struct NODE
{
	struct NODE *link;
	Binary_tree *value;
} Node;

int append(Node *current,Binary_tree* value);
Binary_tree* top(Node *root);

// 二叉树插入
int CreateBinTree(Binary_tree *root,int value,Node *node_root)
{
	// 如果是空树
	if(root->left == NULL && root->right == NULL && root->value == BLANK)
	{
		root->value = value;
		append(node_root,root);
		printf("Insert %c into an empty link list!\n",value);
	}
	else
	{
		// 构造一个新节点
		Binary_tree *new_tree_node = (Binary_tree*)malloc(sizeof(Binary_tree));
		new_tree_node->value = value;
		new_tree_node->left = new_tree_node->right = NULL;
		// 得到链表第一个节点的值
		Binary_tree *current = node_root->link->value;
		// 如果左子树为空
		if(current->left == NULL)
		{
			current->left = new_tree_node;
			append(node_root,current->left);
			printf("Insert %c in parent's left node!\n",value);
		}	
		// 左子树不为空
		else
		{
			current->right = new_tree_node;
			append(node_root,current->right);
			printf("Insert %c in parent's right node!\n",value);
			top(node_root);
		}
	}
	return 0;
}


// 二叉树前序遍历
void pre_print(Binary_tree *root)
{
	if(root->left == NULL && root->right == NULL && root->value < 0)
		return;
	printf("%c ",root->value);
	if(root->left != NULL)
		pre_print(root->left);
	if(root->right != NULL)
		pre_print(root->right);
}

// 二叉树中序遍历
void mid_print(Binary_tree *root)
{
	if(root->left == NULL && root->right == NULL && root->value < 0)
		return;
	if(root->left != NULL)
		pre_print(root->left);
	printf("%c ",root->value);
	if(root->right != NULL)
		pre_print(root->right);
}

// 二叉树后序遍历
void back_print(Binary_tree *root)
{
	if(root->left == NULL && root->right == NULL && root->value < 0)
		return;
	if(root->left != NULL)
		pre_print(root->left);
	if(root->right != NULL)
		pre_print(root->right);
	printf("%c ",root->value);
}

// 弹出链表第一个元素
Binary_tree* top(Node *root)
{
	if(root->link == NULL)
	{
		printf("Can't get top value from empty link list!\n");
		exit(-1);
	}
	Node *current = root->link;
	root->link = current->link;
	return current->value;
}
// 将元素添加到链表末尾
int append(Node *current,Binary_tree* value)
{
	Node *new_node = (Node*)malloc(sizeof(Node));
	new_node->value = value;
	while(current->link != NULL)
	{
		current = current->link;
	}
	current->link = new_node;
	new_node->link = NULL;
	return 0;
}



int main(void)
{
	Binary_tree *root = (Binary_tree*)malloc(sizeof(Binary_tree));
	if(root == NULL)
	{
		printf("Malloc memory failed!\n");
		exit(-1);
	}
	root->left = NULL;
	root->right = NULL;
	root->value = BLANK;
	Node *node_root = (Node*)malloc(sizeof(Node));
	if(node_root == NULL)
	{
		printf("Malloc memory failed!\n");
		exit(-1);
	}
	node_root->link = NULL;
	CreateBinTree(root,'A',node_root);
	CreateBinTree(root,'B',node_root);
	CreateBinTree(root,'C',node_root);
	CreateBinTree(root,'D',node_root);
	CreateBinTree(root,'E',node_root);
	CreateBinTree(root,'F',node_root);
	CreateBinTree(root,'G',node_root);
  
	
	printf("先序遍历: ");
	pre_print(root);
	puts("");
	printf("中序遍历: ");
	mid_print(root);
	puts("");
	printf("后序遍历: ");
	back_print(root);


	free(root);
	return 0;
}

运行截图如下:

在这里插入图片描述

层序生成的二叉树如下所示:

    A
   / \
  B   C
 /\   /\
D  E F  G

3.图

邻接矩阵构造无向图

#include<stdio.h>
 
#include<stdlib.h>
 
/* 最大顶点数 */
#define Max_Vertex_Num 100
 
#define isLetter(a)  ((((a)>='a')&&((a)<='z')) || (((a)>='A')&&((a)<='Z')))
 
 
 
/*
 
arcs[i][j] = 1,表示 "顶点i (即 vexs[i] )" 和 "顶点j (即 vexs[j] )" 是邻接点;
 
arcs[i][j] = 0,表示它们不是邻接点。
 
*/
 
typedef struct{
 
    // 顶点集合,用于保存顶点
    char vexs[Max_Vertex_Num];
 
    // 邻接矩阵
    int arcs[Max_Vertex_Num][Max_Vertex_Num];
 
    //顶点数
    int vexnum;
 
    //边数
    int arcnum;
 
}Mgraph;
 
 
 
 
/*
 * 读取一个输入字符
 */
static char read_char()
{
    char ch;
 
    do {
 
        ch = getchar();
 
    } while(!isLetter(ch));
 
    return ch;
}
 
 
 
/*
 *查找图中顶点的位置(数组中的下标)
 */
int LocateVex(Mgraph *G, char u)
{
    int i;
 
    for(i = 0; i < G->vexnum; ++i)
 
        if(G->vexs[i] == u)
        {
            return i;
        }
 
    return -1;
}
 
 
 
 
/*
 *采用邻接矩阵表示法构造无向图
 */
void BuildGraph(Mgraph *G)
{
 
    int i, j, k, w;
 
    // 顶点
    char v1, v2;
 
 
    printf("请输入要创建的图的顶点数和边数(以空格隔开)\n");
 
    scanf("%d %d", &(G->vexnum), &(G->arcnum));
 
    if ( G->vexnum < 1 || G->arcnum < 1 || (G->arcnum > (G->vexnum * (G->vexnum - 1)) / 2 ) )
    {
        printf("输入错误: 无向图的顶点数或边数无效!\n");
        exit(0);
    }
 
 
    printf("\n请输入要创建的顶点信息:\n");
 
    for(i = 0; i < G->vexnum; i++)
    {
         G->vexs[i] = read_char();
    }
 
 
    // 初始化邻接矩阵
    for(i = 0; i < G->vexnum; i++)
 
        for(j = 0; j < G->vexnum; j++)
 
            G->arcs[i][j] = 0;
 
 
    printf("\n\n请输入要创建的每条边对应的两个顶点及权值w:\n");
 
    for(k = 0;k < G->arcnum; k++)
    {
        printf("\n输入顶点1:");
 
        v1 = read_char();
 
        printf("输入顶点2:");
 
        v2 = read_char();
 
        printf("输入边的权值w:");
 
        scanf("%d", &w);
 
        // 查找顶点v1、v2在图中的位置
        // 即在顶点向量中的下标
        i = LocateVex(G, v1);
 
        j = LocateVex(G, v2);
 
        if((i == -1 || j == -1))
        {
            printf("\n该边无效,请重新输入\n");
        }
        else
        {
            G->arcs[i][j] = w;
            G->arcs[j][i] = w;
 
        }
    }
}
 
 
 
/*
 * 打印矩阵队列图
 */
void print_graph(Mgraph G)
{
    int i, j;
 
    printf("\n\n无向图邻接矩阵:\n");
    for (i = 0; i < G.vexnum; i++)
    {
        for (j = 0; j < G.vexnum; j++)
 
            printf("%d ", G.arcs[i][j]);
 
        printf("\n");
    }
}
 
 
 
 
int main()
{
    Mgraph g;
 
    BuildGraph(&g);
 
    print_graph(g);
 
    return 0;
}
 

运行截图如下:

在这里插入图片描述

特点:

无向图的邻接矩阵一定是对称的,而有向图的邻接矩阵不一定对称。因此,用邻接矩阵来表示一个具有n个顶点的有向图时需要n^2个单元来存储邻接矩阵;对有n个顶点的无向图则只存入上(下)三角阵中剔除了左上右下对角线上的0元素后剩余的元素,故只需1+2+…+(n-1)=n(n-1)/2个单元。

无向图邻接矩阵的第i行(或第i列)非零元素的个数正好是第i个顶点的度。

有向图邻接矩阵中第i行非零元素的个数为第i个顶点的出度,第i列非零元素的个数为第i个顶点的入度,第i个顶点的度为第i行与第i列非零元素个数之和。

用邻接矩阵表示图,很容易确定图中任意两个顶点是否有边相连。

4.总结和思考

数组优于链表的:
1.内存空间占用的少,因为链表节点会附加上一块或两块下一个节点的信息.但是数组在建立时就固定了.所以也有可能会因为建立的数组过大或不足引起内存上的问题.
2.数组内的数据可随机访问.但链表不具备随机访问性.这个很容易理解.数组在内存里是连续的空间.比如如果一个数组地址从100到200,且每个元素占用两个字节,那么100-200之间的任何一个偶数都是数组元素的地址.可以直接访问.链表在内存地址可能是分散的.所以必须通过上一节点中的信息找能找到下一个节点.
3.查找速度上.这个也是因为内存地址的连续性的问题.不罗索了.

链表优于数组的:
1.插入与删除的操作.如果数组的中间插入一个元素,那么这个元素后的所有元素的内存地址都要往后移动.删除的话同理.只有对数据的最后一个元素进行插入删除操作时,才比较快.链表只需要更改有必要更改的节点内的节点信息就够了.并不需要更改节点的内存地址.
2.内存地址的利用率方面.不管你内存里还有多少空间,如果没办法一次性给出数组所需的要空间,那就会提示内存不足,磁盘空间整理的原因之一在这里.而链表可以是分散的空间地址.
3.链表的扩展性比数组好.因为一个数组建立后所占用的空间大小就是固定的.如果满了就没法扩展.只能新建一个更大空间的数组.而链表不是固定的,可以很方便的扩展.

总结:

数组:
优点:使用方便 ,查询效率 比链表高,内存为一连续的区域 
缺点:大小固定,不适合动态存储,不方便动态添加

链表:
优点:可动态添加删除   大小可变   
缺点:只能通过顺次指针访问,查询效率低

统计单词频率思路:

  1. 单词存储 可以用结构体来存放单词的相关信息
  2. 分割字符串 去掉空格、换行符以及各种标点符号
  3. 存放单词 存放单词时应该要判断当前存放的单词是否首次出现
  4. 排序

元素的内存地址都要往后移动.删除的话同理.只有对数据的最后一个元素进行插入删除操作时,才比较快.链表只需要更改有必要更改的节点内的节点信息就够了.并不需要更改节点的内存地址.
2.内存地址的利用率方面.不管你内存里还有多少空间,如果没办法一次性给出数组所需的要空间,那就会提示内存不足,磁盘空间整理的原因之一在这里.而链表可以是分散的空间地址.
3.链表的扩展性比数组好.因为一个数组建立后所占用的空间大小就是固定的.如果满了就没法扩展.只能新建一个更大空间的数组.而链表不是固定的,可以很方便的扩展.

总结:

数组:
优点:使用方便 ,查询效率 比链表高,内存为一连续的区域 
缺点:大小固定,不适合动态存储,不方便动态添加

链表:
优点:可动态添加删除   大小可变   
缺点:只能通过顺次指针访问,查询效率低

统计单词频率思路:

  1. 单词存储 可以用结构体来存放单词的相关信息
  2. 分割字符串 去掉空格、换行符以及各种标点符号
  3. 存放单词 存放单词时应该要判断当前存放的单词是否首次出现
  4. 排序
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值