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.链表的扩展性比数组好.因为一个数组建立后所占用的空间大小就是固定的.如果满了就没法扩展.只能新建一个更大空间的数组.而链表不是固定的,可以很方便的扩展.
总结:
数组:
优点:使用方便 ,查询效率 比链表高,内存为一连续的区域
缺点:大小固定,不适合动态存储,不方便动态添加
链表:
优点:可动态添加删除 大小可变
缺点:只能通过顺次指针访问,查询效率低
统计单词频率思路:
- 单词存储 可以用结构体来存放单词的相关信息
- 分割字符串 去掉空格、换行符以及各种标点符号
- 存放单词 存放单词时应该要判断当前存放的单词是否首次出现
- 排序
元素的内存地址都要往后移动.删除的话同理.只有对数据的最后一个元素进行插入删除操作时,才比较快.链表只需要更改有必要更改的节点内的节点信息就够了.并不需要更改节点的内存地址.
2.内存地址的利用率方面.不管你内存里还有多少空间,如果没办法一次性给出数组所需的要空间,那就会提示内存不足,磁盘空间整理的原因之一在这里.而链表可以是分散的空间地址.
3.链表的扩展性比数组好.因为一个数组建立后所占用的空间大小就是固定的.如果满了就没法扩展.只能新建一个更大空间的数组.而链表不是固定的,可以很方便的扩展.
总结:
数组:
优点:使用方便 ,查询效率 比链表高,内存为一连续的区域
缺点:大小固定,不适合动态存储,不方便动态添加
链表:
优点:可动态添加删除 大小可变
缺点:只能通过顺次指针访问,查询效率低
统计单词频率思路:
- 单词存储 可以用结构体来存放单词的相关信息
- 分割字符串 去掉空格、换行符以及各种标点符号
- 存放单词 存放单词时应该要判断当前存放的单词是否首次出现
- 排序