<think>我们将实现随机推荐功能,包括根据不同的条件(如餐型、菜系、口味等)随机推荐菜谱。
此外,我们还会实现一个功能:根据喜好者推荐他们喜欢的菜。
注意:由于随机推荐需要从符合条件的菜谱中随机选择,我们将使用链表遍历和随机数生成。
文件:random_recommend.c
内容:包含随机推荐菜谱的函数实现</think>以下提供`random_recommend.c`文件的完整实现代码,包含菜谱随机推荐功能的详细实现。这个模块实现了根据多种条件随机推荐菜谱的功能,包括基于餐型、菜系、口味等条件的推荐,以及基于喜好者的个性化推荐。
```c
/* random_recommend.c - 随机推荐功能实现 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "random_recommend.h"
#include "recipe_struct.h"
#include "utils.h"
// 初始化随机数生成器
void init_random() {
static int initialized = 0;
if (!initialized) {
srand(time(NULL));
initialized = 1;
}
}
// 获取随机菜谱
Recipe* get_random_recipe(RecipeNode* head) {
if (head == NULL) return NULL;
init_random();
// 计算链表长度
int count = 0;
RecipeNode* current = head;
while (current != NULL) {
count++;
current = current->next;
}
// 生成随机索引
int random_index = rand() % count;
// 找到对应节点
current = head;
for (int i = 0; i < random_index && current != NULL; i++) {
current = current->next;
}
return (current != NULL) ? &(current->recipe) : NULL;
}
// 按餐型推荐
Recipe* recommend_by_meal_type(RecipeNode* head, MealType meal_type) {
if (head == NULL) return NULL;
init_random();
// 计算符合条件的菜谱数量
int count = 0;
RecipeNode* current = head;
while (current != NULL) {
if (current->recipe.meal_type == meal_type) {
count++;
}
current = current->next;
}
if (count == 0) return NULL;
// 生成随机索引
int random_index = rand() % count;
// 找到对应节点
current = head;
int found = 0;
while (current != NULL) {
if (current->recipe.meal_type == meal_type) {
if (found == random_index) {
return &(current->recipe);
}
found++;
}
current = current->next;
}
return NULL;
}
// 按菜系推荐
Recipe* recommend_by_cuisine(RecipeNode* head, CuisineType cuisine) {
if (head == NULL) return NULL;
init_random();
// 计算符合条件的菜谱数量
int count = 0;
RecipeNode* current = head;
while (current != NULL) {
if (current->recipe.cuisine == cuisine) {
count++;
}
current = current->next;
}
if (count == 0) return NULL;
// 生成随机索引
int random_index = rand() % count;
// 找到对应节点
current = head;
int found = 0;
while (current != NULL) {
if (current->recipe.cuisine == cuisine) {
if (found == random_index) {
return &(current->recipe);
}
found++;
}
current = current->next;
}
return NULL;
}
// 按口味推荐
Recipe* recommend_by_flavors(RecipeNode* head, int flavors) {
if (head == NULL) return NULL;
init_random();
// 计算符合条件的菜谱数量
int count = 0;
RecipeNode* current = head;
while (current != NULL) {
// 检查是否包含所有请求的口味
if ((current->recipe.flavors & flavors) == flavors) {
count++;
}
current = current->next;
}
if (count == 0) return NULL;
// 生成随机索引
int random_index = rand() % count;
// 找到对应节点
current = head;
int found = 0;
while (current != NULL) {
if ((current->recipe.flavors & flavors) == flavors) {
if (found == random_index) {
return &(current->recipe);
}
found++;
}
current = current->next;
}
return NULL;
}
// 按状态推荐
Recipe* recommend_by_textures(RecipeNode* head, int textures) {
if (head == NULL) return NULL;
init_random();
// 计算符合条件的菜谱数量
int count = 0;
RecipeNode* current = head;
while (current != NULL) {
// 检查是否包含所有请求的状态
if ((current->recipe.textures & textures) == textures) {
count++;
}
current = current->next;
}
if (count == 0) return NULL;
// 生成随机索引
int random_index = rand() % count;
// 找到对应节点
current = head;
int found = 0;
while (current != NULL) {
if ((current->recipe.textures & textures) == textures) {
if (found == random_index) {
return &(current->recipe);
}
found++;
}
current = current->next;
}
return NULL;
}
// 按喜好者推荐
Recipe* recommend_by_lover(RecipeNode* head, const char* lover_name) {
if (head == NULL || lover_name == NULL || *lover_name == '\0')
return NULL;
init_random();
// 计算符合条件的菜谱数量
int count = 0;
RecipeNode* current = head;
while (current != NULL) {
// 检查喜好者字符串中是否包含指定名称
if (strstr(current->recipe.lovers, lover_name) != NULL) {
count++;
}
current = current->next;
}
if (count == 0) return NULL;
// 生成随机索引
int random_index = rand() % count;
// 找到对应节点
current = head;
int found = 0;
while (current != NULL) {
if (strstr(current->recipe.lovers, lover_name) != NULL) {
if (found == random_index) {
return &(current->recipe);
}
found++;
}
current = current->next;
}
return NULL;
}
// 综合推荐
Recipe* comprehensive_recommend(RecipeNode* head,
MealType meal_type,
CuisineType cuisine,
int flavors,
int textures,
const char* lover_name)
{
if (head == NULL) return NULL;
init_random();
// 计算符合条件的菜谱数量
int count = 0;
RecipeNode* current = head;
while (current != NULL) {
int match = 1;
// 检查餐型
if (meal_type != -1 && current->recipe.meal_type != meal_type) {
match = 0;
}
// 检查菜系
if (match && cuisine != -1 && current->recipe.cuisine != cuisine) {
match = 0;
}
// 检查口味
if (match && flavors != 0 && (current->recipe.flavors & flavors) != flavors) {
match = 0;
}
// 检查状态
if (match && textures != 0 && (current->recipe.textures & textures) != textures) {
match = 0;
}
// 检查喜好者
if (match && lover_name != NULL && *lover_name != '\0' &&
strstr(current->recipe.lovers, lover_name) == NULL) {
match = 0;
}
if (match) {
count++;
}
current = current->next;
}
if (count == 0) return NULL;
// 生成随机索引
int random_index = rand() % count;
// 找到对应节点
current = head;
int found = 0;
while (current != NULL) {
int match = 1;
if (meal_type != -1 && current->recipe.meal_type != meal_type) {
match = 0;
}
if (match && cuisine != -1 && current->recipe.cuisine != cuisine) {
match = 0;
}
if (match && flavors != 0 && (current->recipe.flavors & flavors) != flavors) {
match = 0;
}
if (match && textures != 0 && (current->recipe.textures & textures) != textures) {
match = 0;
}
if (match && lover_name != NULL && *lover_name != '\0' &&
strstr(current->recipe.lovers, lover_name) == NULL) {
match = 0;
}
if (match) {
if (found == random_index) {
return &(current->recipe);
}
found++;
}
current = current->next;
}
return NULL;
}
// 随机推荐菜单
void random_recommend_menu(RecipeNode* recipe_head, LoverNode* lover_head) {
int choice;
do {
printf("\n=== 随机推荐 ===\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");
choice = get_int_input("请选择推荐方式: ");
if (choice == -1 || choice == 0) break;
Recipe* recommended = NULL;
switch (choice) {
case 1: // 完全随机
recommended = get_random_recipe(recipe_head);
break;
case 2: { // 按餐型
MealType meal_type = get_meal_type();
if (meal_type == -1) break;
recommended = recommend_by_meal_type(recipe_head, meal_type);
break;
}
case 3: { // 按菜系
CuisineType cuisine = get_cuisine_type();
if (cuisine == -1) break;
recommended = recommend_by_cuisine(recipe_head, cuisine);
break;
}
case 4: { // 按口味
int flavors = get_flavors();
if (flavors == 0) {
printf("未选择任何口味!\n");
break;
}
recommended = recommend_by_flavors(recipe_head, flavors);
break;
}
case 5: { // 按状态
int textures = get_textures();
if (textures == 0) {
printf("未选择任何状态!\n");
break;
}
recommended = recommend_by_textures(recipe_head, textures);
break;
}
case 6: { // 按喜好者
char lover_name[100];
if (lover_head == NULL) {
printf("喜好者列表为空!\n");
break;
}
// 显示所有喜好者
print_all_lovers(lover_head);
get_string_input("输入喜好者姓名: ", lover_name, sizeof(lover_name));
if (lover_name[0] == '\0') break;
recommended = recommend_by_lover(recipe_head, lover_name);
break;
}
case 7: { // 综合条件
MealType meal_type = -1;
CuisineType cuisine = -1;
int flavors = 0;
int textures = 0;
char lover_name[100] = {0};
// 收集条件
if (yes_no_prompt("是否指定餐型?")) {
meal_type = get_meal_type();
}
if (yes_no_prompt("是否指定菜系?")) {
cuisine = get_cuisine_type();
}
if (yes_no_prompt("是否指定口味?")) {
flavors = get_flavors();
}
if (yes_no_prompt("是否指定状态?")) {
textures = get_textures();
}
if (lover_head != NULL && yes_no_prompt("是否指定喜好者?")) {
print_all_lovers(lover_head);
get_string_input("输入喜好者姓名: ", lover_name, sizeof(lover_name));
}
recommended = comprehensive_recommend(recipe_head, meal_type,
cuisine, flavors, textures,
lover_name);
break;
}
default:
printf("无效选择!\n");
}
// 显示推荐结果
if (recommended != NULL) {
printf("\n=== 为您推荐 ===\n");
print_recipe_details(recommended);
} else {
printf("\n没有找到符合条件的菜谱!\n");
}
// 继续推荐
if (choice != 0 && !yes_no_prompt("是否继续推荐?")) {
break;
}
} while (choice != 0);
}
```
### 功能详细说明
#### 1. 随机数初始化
- **函数**:`init_random()`
- **功能**:使用当前时间初始化随机数生成器
- **特点**:
- 使用静态变量确保只初始化一次
- 避免重复推荐相同序列
#### 2. 基础推荐功能
1. **完全随机推荐**:
- 从所有菜谱中随机选择
- 实现:`get_random_recipe()`
2. **按餐型推荐**:
- 随机选择指定餐型的菜谱
- 实现:`recommend_by_meal_type()`
3. **按菜系推荐**:
- 随机选择指定菜系的菜谱
- 实现:`recommend_by_cuisine()`
4. **按口味推荐**:
- 随机选择包含所有指定口味的菜谱
- 使用位掩码技术高效匹配
- 实现:`recommend_by_flavors()`
5. **按状态推荐**:
- 随机选择包含所有指定状态的菜谱
- 使用位掩码技术高效匹配
- 实现:`recommend_by_textures()`
6. **按喜好者推荐**:
- 随机选择指定喜好者喜欢的菜谱
- 使用字符串匹配查找喜好者
- 实现:`recommend_by_lover()`
#### 3. 高级推荐功能
- **综合推荐**:`comprehensive_recommend()`
- 支持多条件组合:
- 餐型
- 菜系
- 口味
- 状态
- 喜好者
- 条件可选(使用特殊值表示忽略)
- 所有条件使用AND逻辑组合
#### 4. 用户交互菜单
- **功能**:`random_recommend_menu()`
- **特点**:
- 7种推荐方式选择
- 交互式条件输入
- 结果即时显示
- 支持连续推荐
- 自动处理空结果
### 算法实现细节
1. **两阶段随机选择**:
```c
// 第一阶段:计算符合条件的菜谱数量
int count = 0;
RecipeNode* current = head;
while (current != NULL) {
if (/* 匹配条件 */) {
count++;
}
current = current->next;
}
// 第二阶段:随机选择
if (count > 0) {
int random_index = rand() % count;
current = head;
int found = 0;
while (current != NULL) {
if (/* 匹配条件 */) {
if (found == random_index) {
return &(current->recipe);
}
found++;
}
current = current->next;
}
}
```
2. **位掩码匹配**:
```c
// 检查是否包含所有指定口味
if ((current->recipe.flavors & flavors) == flavors) {
// 匹配成功
}
```
3. **字符串部分匹配**:
```c
// 检查喜好者是否包含指定名称
if (strstr(current->recipe.lovers, lover_name) != NULL) {
// 匹配成功
}
```
4. **条件组合处理**:
```c
int match = 1;
// 餐型检查
if (meal_type != -1 && current->recipe.meal_type != meal_type) {
match = 0;
}
// 菜系检查
if (match && cuisine != -1 && current->recipe.cuisine != cuisine) {
match = 0;
}
// 其他条件检查...
if (match) {
// 符合所有条件
}
```
### 关键设计特点
1. **高效随机算法**:
- O(n)时间复杂度完成随机选择
- 只需遍历链表两次(计数+选择)
- 内存使用恒定(O(1)额外空间)
2. **灵活的条件处理**:
- 使用特殊值(-1, 0, NULL)表示忽略条件
- 位掩码实现高效多值匹配
- 支持任意条件组合
3. **健壮的错误处理**:
- 空链表检测
- 无效输入处理
- 无匹配结果处理
- 边界条件检查
4. **用户友好交互**:
- 清晰的菜单导航
- 分步条件输入
- 结果格式化显示
- 连续操作支持
### 使用示例
```text
=== 随机推荐 ===
1. 完全随机推荐
2. 按餐型推荐
3. 按菜系推荐
4. 按口味推荐
5. 按状态推荐
6. 按喜好者推荐
7. 综合条件推荐
0. 返回主菜单
请选择推荐方式: 7
是否指定餐型?(y/n): y
餐型选择:
1.早餐 2.正餐 3.甜品 4.零食 5.饮品
请选择餐型(1-5): 2
是否指定菜系?(y/n): y
菜系选择:
1.鲁菜 2.川菜 3.粤菜 4.苏菜 5.闽菜
6.浙菜 7.湘菜 8.徽菜 9.东北菜 10.家常菜 11.西餐
请选择菜系(1-11): 2
是否指定口味?(y/n): y
口味选择(多选,输入0结束):
1.酸 2.甜 3.苦 4.辣 5.咸 6.凉 7.热
选择口味(1-7, 0结束): 1
选择口味(1-7, 0结束): 4
选择口味(1-7, 0结束): 0
是否指定状态?(y/n): n
是否指定喜好者?(y/n): y
=== 喜好者列表 ===
1. 张三
2. 李四
3. 王五
输入喜好者姓名: 李四
=== 为您推荐 ===
========== 菜谱详情 ==========
ID: 1001
菜名: 鱼香肉丝
餐型: 正餐
口味: 酸,辣
状态: 软
菜系: 川菜
食材: 猪肉;木耳;胡萝卜;青椒
步骤: 切丝;腌制;炒制;调味
时间: 30分钟
喜好者: 张三;李四
==============================
是否继续推荐?(y/n): n
```