#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//定义链表节点
typedef struct RecordNode {
int year, month, day; //记录日期
float amount; //金额
int type; //支出种类,0表示收入,1表示支出
char detail[100]; //详细描述
struct RecordNode *next; //指向下一个节点的指针
} RecordNode;
//显示菜单
void showMenu() {
printf("1. 添加收入记录\n");
printf("2. 添加支出记录\n");
printf("3. 查看收支情况\n");
printf("4. 设置预算\n");
printf("5. 管理预算\n");
printf("6. 生成报表统计\n");
printf("7. 可视化展示\n");
printf("8. 退出\n");
printf("请选择:\n");
}
//添加记录
RecordNode* addRecord(RecordNode *head) {
RecordNode *p, *q;
q = (RecordNode*)malloc(sizeof(RecordNode)); //为新节点分配内存
printf("请输入年月日,格式为yyyy-mm-dd:\n");
scanf("%d-%d-%d", &q->year, &q->month, &q->day);
printf("请输入金额:\n");
scanf("%f", &q->amount);
printf("请选择类型(0表示收入,1表示支出):\n");
scanf("%d", &q->type);
printf("请输入详细描述:\n");
scanf("%s", q->detail);
q->next = NULL;
//找到链表尾部,并将新节点添加到链表末尾
if (head == NULL) {
head = q;
}
else {
p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = q;
}
printf("记录添加成功!\n");
return head;
}
//查看收支情况
void showRecord(RecordNode *head) {
RecordNode *p;
float income = 0, expense = 0; //收入和支出金额
printf("日期\t\t\t金额\t\t类型\t\t描述\n");
for (p = head; p != NULL; p = p->next) {
printf("%d-%02d-%02d\t%.2f\t\t", p->year, p->month, p->day, p->amount);
if (p->type == 0) {
printf("收入\t\t");
income += p->amount;
}
else {
printf("支出\t\t");
expense += p->amount;
}
printf("%s\n", p->detail);
}
printf("总收入为:%.2f元,总支出为:%.2f元,净收入为:%.2f元\n", income, expense, income - expense);
}
//设置预算
void setBudget(float *budget) {
printf("请输入本月预算:\n");
scanf("%f", budget);
printf("预算设置为:%.2f元\n", *budget);
}
//管理预算
void manageBudget(RecordNode *head, float budget) {
RecordNode *p;
float totalExpense = 0; //当月总支出
int controlFlag = 0; //是否需要控制支出的标志
for (p = head; p != NULL; p = p->next) {
if (p->year == 2022 && p->month == 1) { //只统计当前月的记录
if (p->type == 1) {
totalExpense += p->amount;
if (p->amount > budget / 30) { //超出每日预算50元,需要控制支出
controlFlag = 1;
}
}
}
}
printf("本月总支出为:%.2f元,预算剩余:%.2f元\n", totalExpense, budget - totalExpense);
if (controlFlag) {
printf("警告:某些支出超过每日控制金额,需要控制支出!\n");
}
}
//生成报表统计
void generateReport(RecordNode *head) {
int incomeCount = 0, expenseCount = 0;
float incomeSum = 0, expenseSum = 0;
int typeCount[10] = { 0 }; //不同类型的支出数量,最多支持10种类型
RecordNode *p;
for (p = head; p != NULL; p = p->next) {
if (p->type == 0) {
incomeSum += p->amount;
incomeCount++;
}
else {
expenseSum += p->amount;
expenseCount++;
typeCount[p->type - 1]++;
}
}
printf("报表统计如下:\n");
printf("当月总收入为:%.2f元,总支出为:%.2f元,净收入为:%.2f元\n", incomeSum, expenseSum, incomeSum - expenseSum);
printf("当月共有%d条收入记录,%d条支出记录\n", incomeCount, expenseCount);
printf("支出类别如下:\n");
for (int i = 0; i < 10; i++) {
if (typeCount[i] != 0) {
printf("支出类别%d:%.2f元,占比%.2f%%\n", i + 1, typeCount[i], typeCount[i] * 100.0 / expenseCount);
}
}
}
//可视化展示
void visualize(RecordNode *head) {
int count[10] = { 0 }; //不同类型支出的数量
float expense = 0; //总支出
RecordNode *p;
//统计不同类型支出的数量和总支出
for (p = head; p != NULL; p = p->next) {
if (p->type == 1) { //只统计支出
expense += p->amount;
count[p->type - 1]++; //支出类型从1开始,需要减1对应数组下标
}
}
printf("当前月份支出总额为:%.2f元\n", expense);
printf("支出类别比例如下:\n");
//输出饼图
float percent;
for (int i = 0; i < 10; i++) {
if (count[i] != 0) {
percent = count[i] * 100.0 / expense; //计算支出占比
printf("类型%d:", i + 1);
for (int j = 1; j <= percent / 2; j++) { //占比每增加2%,输出一个"*"
printf("*");
}
printf(" %.2f%%\n", percent);
}
}
}
int main() {
RecordNode *head = NULL; //链表为空
int choice;
float budget = 0; //预算初始值为0
do {
showMenu();
scanf("%d", &choice);
switch (choice) {
case 1:
head = addRecord(head);
break;
case 2:
head = addRecord(head);
break;
case 3:
showRecord(head);
break;
case 4:
setBudget(&budget);
break;
case 5:
manageBudget(head, budget);
break;
case 6:
generateReport(head);
break;
case 7:
visualize(head);
break;
case 8:
printf("感谢使用,再见!\n");
break;
default:
printf("输入有误,请重新输入!\n");
break;
}
} while (choice != 8);
//释放链表内存
RecordNode *p = head, *q;
while (p != NULL) {
q = p->next;
free(p);
p = q;
}
return 0;
}
欢迎订阅专栏,数据结构实验,期末大作业,前端后端都有哦,想我发哪个方面的资源或文章可以私信我,免费的哦