From cf648f6bf9cba1821888013fb41191e444b4e73f Mon Sep 17 00:00:00 2001 From: guyuan Date: Fri, 22 May 2026 16:09:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=E3=80=8C/=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- house_operation.py | 160 ++++++++++----------- house_service.py | 348 +++++++++++++++++++++++++++------------------ main.py | 185 ++++++++++++++++++++++++ 3 files changed, 470 insertions(+), 223 deletions(-) create mode 100644 main.py diff --git a/house_operation.py b/house_operation.py index f49287e..5963fec 100644 --- a/house_operation.py +++ b/house_operation.py @@ -1,83 +1,77 @@ -import json -import os - -# 以下为 V1.0 原有代码,完全未修改 - -# 定义数据文件路径 -HOUSE_FILE = "./data/houses.json" - -def init_db(): - """ - 初始化数据文件:如果houses.json不存在,创建并写入空列表 - 空间复杂度:O(1)(仅创建空文件) - """ - # 确保data文件夹存在 - os.makedirs("./data", exist_ok=True) - # 如果文件不存在,创建并写入空列表 - if not os.path.exists(HOUSE_FILE): - with open(HOUSE_FILE, 'w', encoding='utf-8') as f: - json.dump([], f, ensure_ascii=False, indent=4) - -def read_houses(): - """ - 读取所有房源数据 - 时间复杂度:O(n)(n为房源数,JSON解析耗时与数据量正相关) - 空间复杂度:O(n)(存储所有房源数据) - return: 房源列表(每个元素是字典) - """ - init_db() # 先确保文件存在 - with open(HOUSE_FILE, 'r', encoding='utf-8') as f: - return json.load(f) - -def write_houses(houses): - """ - 写入房源数据到JSON文件 - 时间复杂度:O(n)(n为房源数,JSON序列化耗时与数据量正相关) - 空间复杂度:O(1)(仅写入操作,无额外存储) - param houses: 要写入的房源列表 - """ - with open(HOUSE_FILE, 'w', encoding='utf-8') as f: - json.dump(houses, f, ensure_ascii=False, indent=4) - -# V2.0 新增代码:栈数据读写 - -# V2.0 新增:栈数据文件配置 -STACK_FILE = "./data/stack_data.json" - -# V2.0 新增:栈数据初始化与读写 -def init_stack_db(): - """ - 初始化栈数据文件:若不存在则创建,区分操作记录栈/浏览历史栈 - """ - os.makedirs("./data", exist_ok=True) - if not os.path.exists(STACK_FILE): - init_data = { - "operation_stack": [], - "browse_stack": [] - } - with open(STACK_FILE, 'w', encoding='utf-8') as f: - json.dump(init_data, f, ensure_ascii=False, indent=4) - -def read_stack(stack_type): - """ - 读取指定类型的栈数据 - :param stack_type: operation(操作记录)/ browse(浏览历史) - """ - init_stack_db() - with open(STACK_FILE, 'r', encoding='utf-8') as f: - data = json.load(f) - stack_key = f"{stack_type}_stack" - return data.get(stack_key, []) - -def write_stack(stack_type, new_stack): - """ - 写入指定类型的栈数据到文件 - """ - init_stack_db() - # 读取原有数据,避免覆盖另一个栈 - with open(STACK_FILE, 'r', encoding='utf-8') as f: - data = json.load(f) - stack_key = f"{stack_type}_stack" - data[stack_key] = new_stack - with open(STACK_FILE, 'w', encoding='utf-8') as f: - json.dump(data, f, ensure_ascii=False, indent=4) \ No newline at end of file +import json +import os + +HOUSE_FILE = "./data/houses.json" + +def init_db(): + """初始化房源数据文件""" + os.makedirs("./data", exist_ok=True) + if not os.path.exists(HOUSE_FILE): + with open(HOUSE_FILE, 'w', encoding='utf-8') as f: + json.dump([], f, ensure_ascii=False, indent=4) + +def read_houses(): + """读取所有房源""" + init_db() + with open(HOUSE_FILE, 'r', encoding='utf-8') as f: + return json.load(f) + +def write_houses(houses): + """写入房源""" + with open(HOUSE_FILE, 'w', encoding='utf-8') as f: + json.dump(houses, f, ensure_ascii=False, indent=4) + +STACK_FILE = "./data/stack_data.json" + +def init_stack_db(): + """初始化栈文件""" + os.makedirs("./data", exist_ok=True) + if not os.path.exists(STACK_FILE): + init_data = {"operation_stack": [], "browse_stack": []} + with open(STACK_FILE, 'w', encoding='utf-8') as f: + json.dump(init_data, f, ensure_ascii=False, indent=4) + +def read_stack(stack_type): + """读取指定栈""" + init_stack_db() + with open(STACK_FILE, 'r', encoding='utf-8') as f: + data = json.load(f) + return data.get(f"{stack_type}_stack", []) + +def write_stack(stack_type, new_stack): + """写入指定栈""" + init_stack_db() + with open(STACK_FILE, 'r', encoding='utf-8') as f: + data = json.load(f) + data[f"{stack_type}_stack"] = new_stack + with open(STACK_FILE, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=4) + +# V3.0 字符串+数组:邻接矩阵数据读写 +MATRIX_FILE = "./data/matrix.json" + +def init_matrix_db(): + """ + 新增:初始化小区邻接矩阵文件 + 存储所有小区名称列表 和 二维距离数组(邻接矩阵) + """ + os.makedirs("./data", exist_ok=True) + if not os.path.exists(MATRIX_FILE): + init_data = { + "community_list": [], # 小区名称列表(一维数组) + "distance_matrix": [] # 小区距离二维数组(邻接矩阵) + } + with open(MATRIX_FILE, 'w', encoding='utf-8') as f: + json.dump(init_data, f, ensure_ascii=False, indent=4) + +def read_matrix_data(): + """V3.0新增读取小区列表和距离邻接矩阵""" + init_matrix_db() + with open(MATRIX_FILE, 'r', encoding='utf-8') as f: + return json.load(f) + +def write_matrix_data(matrix_dict): + """V3.0新增保存小区列表和距离邻接矩阵""" + init_matrix_db() + with open(MATRIX_FILE, 'w', encoding='utf-8') as f: + json.dump(matrix_dict, f, ensure_ascii=False, indent=4) \ No newline at end of file diff --git a/house_service.py b/house_service.py index 4da03e8..3202919 100644 --- a/house_service.py +++ b/house_service.py @@ -1,140 +1,208 @@ -from house.db_operation import read_houses, write_houses - - -def get_next_house_id(): - """ - 生成下一个房源ID(保证ID唯一) - 时间复杂度:O(n)(遍历所有房源找最大ID) - return: 下一个可用的ID(整数) - """ - houses = read_houses() - if not houses: - return 1 # 无房源时,第一个ID为1 - # 找到最大ID,加1作为新ID - max_id = max(house["id"] for house in houses) - return max_id + 1 - - -def add_house(address, price, area, house_type): - """ - 新增房源(线性表的尾部插入操作) - 时间复杂度:O(n)(read/write各O(n),整体O(n)) - 空间复杂度:O(n)(存储所有房源数据) - param address: 房源地址(字符串) - param price: 租金(整数/浮点数) - param area: 面积(整数/浮点数) - param house_type: 户型(字符串,如"一居室") - return: 新增成功返回True,失败返回False - """ - # 基础数据校验(非空+数值合法性) - if not address or not house_type: - print("错误:地址和户型不能为空!") - return False - if not isinstance(price, (int, float)) or price <= 0: - print("错误:租金必须是正数!") - return False - if not isinstance(area, (int, float)) or area <= 0: - print("错误:面积必须是正数!") - return False - - # 构建新房源字典(线性表的元素) - new_house = { - "id": get_next_house_id(), - "address": address, - "price": price, - "area": area, - "house_type": house_type - } - - # 读取现有房源(线性表),新增元素(尾部插入) - houses = read_houses() - houses.append(new_house) # 线性表append操作,时间复杂度O(1) - - # 写入文件 - write_houses(houses) - print(f"房源新增成功!房源ID:{new_house['id']}") - return True - - -def delete_house(house_id): - """ - 删除房源(线性表的指定位置删除操作) - 时间复杂度:O(n)(遍历找ID+写入文件,整体O(n)) - 空间复杂度:O(n)(存储所有房源数据) - param house_id: 要删除的房源ID(整数) - return: 删除成功返回True,失败返回False - """ - houses = read_houses() - # 遍历线性表,找到对应ID的房源 - for index, house in enumerate(houses): - if house["id"] == house_id: - del houses[index] # 线性表删除操作,时间复杂度O(n)(后续元素前移) - write_houses(houses) - print(f"房源ID {house_id} 删除成功!") - return True - print(f"错误:未找到房源ID {house_id}!") - return False - - -def update_house(house_id, new_info): - """ - 修改房源信息(线性表的指定元素更新操作) - 时间复杂度:O(n)(遍历找ID+写入文件,整体O(n)) - 空间复杂度:O(n)(存储所有房源数据) - param house_id: 要修改的房源ID(整数) - param new_info: 要修改的字段字典(如{"price": 5500, "area": 85}) - return: 修改成功返回True,失败返回False - """ - houses = read_houses() - # 遍历线性表,找到对应ID的房源 - for house in houses: - if house["id"] == house_id: - # 仅更新传入的有效字段 - for key, value in new_info.items(): - if key in ["address", "price", "area", "house_type"]: - # 校验数值字段合法性 - if key in ["price", "area"]: - if not isinstance(value, (int, float)) or value <= 0: - print(f"错误:{key}必须是正数!") - return False - house[key] = value - write_houses(houses) - print(f"房源ID {house_id} 修改成功!") - return True - print(f"错误:未找到房源ID {house_id}!") - return False - - -def query_house(condition_type, condition_value): - """ - 查询房源(线性表的遍历筛选操作) - 时间复杂度:O(n)(遍历所有房源,n为房源数) - 空间复杂度:O(k)(k为符合条件的房源数,最坏O(n)) - param condition_type: 查询条件类型("id"/"address"/"price"/"house_type") - param condition_value: 查询条件值 - return: 符合条件的房源列表 - """ - houses = read_houses() - result = [] - # 按条件遍历筛选 - for house in houses: - # 处理ID查询(整数匹配) - if condition_type == "id": - if house["id"] == int(condition_value): - result.append(house) - # 处理地址查询(模糊匹配) - elif condition_type == "address": - if condition_value in house["address"]: - result.append(house) - # 处理户型查询(精确匹配) - elif condition_type == "house_type": - if house["house_type"] == condition_value: - result.append(house) - # 处理租金查询(数值匹配,示例:查询等于该价格的房源) - elif condition_type == "price": - if house["price"] == float(condition_value): - result.append(house) - else: - print("错误:不支持的查询条件类型!") - return [] - return result \ No newline at end of file +from house_operation import * +from datetime import datetime + +def get_next_house_id(): + houses = read_houses() + if not houses: + return 1 + max_id = max(house["id"] for house in houses) + return max_id + 1 + +def add_house(address, price, area, house_type): + if not address or not house_type: + print("错误:地址和户型不能为空!") + return False + if not isinstance(price, (int, float)) or price <= 0: + print("错误:租金必须是正数!") + return False + if not isinstance(area, (int, float)) or area <= 0: + print("错误:面积必须是正数!") + return False + + new_house = { + "id": get_next_house_id(), + "address": address, + "price": price, + "area": area, + "house_type": house_type + } + houses = read_houses() + houses.append(new_house) + write_houses(houses) + print(f"房源新增成功!房源ID:{new_house['id']}") + return True + +def delete_house(house_id): + houses = read_houses() + for index, house in enumerate(houses): + if house["id"] == house_id: + del houses[index] + write_houses(houses) + print(f"房源ID {house_id} 删除成功!") + return True + print(f"错误:未找到房源ID {house_id}!") + return False + +def update_house(house_id, new_info): + houses = read_houses() + for house in houses: + if house["id"] == house_id: + for key, value in new_info.items(): + if key in ["address", "price", "area", "house_type"]: + if key in ["price", "area"]: + if not isinstance(value, (int, float)) or value <= 0: + print(f"错误:{key}必须是正数!") + return False + house[key] = value + write_houses(houses) + print(f"房源ID {house_id} 修改成功!") + return True + print(f"错误:未找到房源ID {house_id}!") + return False + +def query_house(condition_type, condition_value): + houses = read_houses() + result = [] + for house in houses: + if condition_type == "id": + if house["id"] == int(condition_value): + result.append(house) + elif condition_type == "address": + if condition_value in house["address"]: + result.append(house) + elif condition_type == "house_type": + if house["house_type"] == condition_value: + result.append(house) + elif condition_type == "price": + if house["price"] == float(condition_value): + result.append(house) + else: + print("错误:不支持的查询条件类型!") + return [] + return result + +MAX_STACK_LENGTH = 100 + +def push_operation_stack(operation_info): + time_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + full_info = f"[{time_str}] {operation_info}" + stack = read_stack("operation") + stack.append(full_info) + if len(stack) > MAX_STACK_LENGTH: + stack.pop(0) + write_stack("operation", stack) + +def push_browse_stack(house_id): + stack = read_stack("browse") + if stack and stack[-1] == house_id: + return + stack.append(house_id) + if len(stack) > MAX_STACK_LENGTH: + stack.pop(0) + write_stack("browse", stack) + +def pop_operation_stack(): + stack = read_stack("operation") + if not stack: + return None + latest_op = stack.pop() + write_stack("operation", stack) + return latest_op + +def pop_browse_stack(): + stack = read_stack("browse") + if not stack: + return None + latest_hid = stack.pop() + write_stack("browse", stack) + return latest_hid + +def get_recent_records(stack_type, limit=10): + stack = read_stack(stack_type) + return stack[-limit:][::-1] + +def clear_stack(stack_type): + write_stack(stack_type, []) + print(f"{stack_type}记录已清空!") + +def parse_address_string(full_address): + + # 字符串分割(串操作核心) + parts = full_address.split("市") + province_city = parts[0] + "市" if "市" in full_address else parts[0] + if "省" in province_city: + province, city = province_city.split("省") + province += "省" + city += "市" + else: + province = "未知省份" + city = province_city + + # 继续拆分区县 + if len(parts) > 1: + district_part = parts[1] + if "区" in district_part or "县" in district_part: + district, community = district_part.split("区") if "区" in district_part else district_part.split("县") + district += "区" if "区" in district_part else "县" + else: + district = "未知区县" + community = district_part + else: + district = "未知区县" + community = "未知小区" + + return { + "province": province, + "city": city, + "district": district, + "community": community + } + +def fuzzy_query_by_district(keyword): + + houses = read_houses() + result = [] + for house in houses: + addr_info = parse_address_string(house["address"]) + # 字符串包含匹配 + if keyword in addr_info["district"] or keyword in addr_info["community"]: + result.append(house) + return result + +def init_community_matrix(community_name_list): + """ + 【V3.0新增 二维数组知识点:邻接矩阵初始化】 + 根据小区列表生成距离邻接矩阵,初始化距离为无穷大,自己到自己为0 + 时间复杂度:O(N²),N为小区数量 + 空间复杂度:O(N²) + """ + INF = float("inf") + n = len(community_name_list) + # 二维数组初始化(邻接矩阵) + distance_matrix = [[INF]*n for _ in range(n)] + for i in range(n): + distance_matrix[i][i] = 0 # 自己到自己距离为0 + + # 保存到数据文件 + matrix_data = { + "community_list": community_name_list, + "distance_matrix": distance_matrix + } + write_matrix_data(matrix_data) + print("邻接矩阵初始化完成!") + +def update_matrix_distance(community_a, community_b, distance): + + matrix_data = read_matrix_data() + community_list = matrix_data["community_list"] + distance_matrix = matrix_data["distance_matrix"] + + try: + idx_a = community_list.index(community_a) + idx_b = community_list.index(community_b) + distance_matrix[idx_a][idx_b] = distance + distance_matrix[idx_b][idx_a] = distance + write_matrix_data(matrix_data) + print(f"{community_a} <-> {community_b} 距离更新成功!") + except ValueError: + print("小区名称不存在!") \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..23ea4e2 --- /dev/null +++ b/main.py @@ -0,0 +1,185 @@ +from house_service import * + +def print_menu(): + print("\n===== 房屋出租系统 V3.0 =====") + print("1. 新增房源") + print("2. 删除房源") + print("3. 修改房源") + print("4. 查询房源") + print("5. 查看/管理操作记录") + print("6. 查看/管理浏览历史") + # V3.0 新增菜单 + print("7. 地址字符串解析测试") + print("8. 按区域关键词模糊查询") + print("9. 初始化小区邻接矩阵") + print("10. 更新小区间距离") + print("11. 退出系统") + print("============================") + +def op_record_menu(): + while True: + print("\n----- 操作记录管理 -----") + print("1. 查看最近10条") + print("2. 取出最新一条") + print("3. 清空记录") + print("4. 返回") + c = input("请选择:") + if c == "1": + lst = get_recent_records("operation",10) + print(lst if lst else "暂无记录") + elif c == "2": + print(pop_operation_stack() or "暂无记录") + elif c == "3": + clear_stack("operation") + elif c == "4": + break + else: + print("输入有误") + + +def browse_history_menu(): + while True: + print("\n----- 浏览历史管理 -----") + print("1. 查看最近10条") + print("2. 取出最新一条") + print("3. 清空历史") + print("4. 返回") + c = input("请选择:") + if c == "1": + id_list = get_recent_records("browse",10) + if not id_list: + print("暂无浏览历史") + continue + for idx,hid in enumerate(id_list,1): + info = query_house("id", hid) + if info: + h = info[0] + print(f"{idx}. ID:{hid} 地址:{h['address']}") + else: + print(f"{idx}. ID:{hid} 房源已不存在") + elif c == "2": + hid = pop_browse_stack() + if not hid: + print("暂无浏览历史") + continue + info = query_house("id", hid) + print(f"最近浏览ID:{hid}") + elif c == "3": + clear_stack("browse") + elif c == "4": + break + else: + print("输入有误") + + +def main(): + while True: + print_menu() + choice = input("请输入功能编号:") + + if choice == "1": + addr = input("输入房源地址:") + try: + price = float(input("输入月租金:")) + area = float(input("输入面积:")) + except: + print("租金面积必须是数字!") + continue + htype = input("输入户型:") + if add_house(addr,price,area,htype): + new_id = get_next_house_id() - 1 + push_operation_stack(f"新增房源ID:{new_id} 地址:{addr}") + + elif choice == "2": + try: + hid = int(input("输入要删除房源ID:")) + res = query_house("id",hid) + addr = res[0]["address"] if res else "未知地址" + if delete_house(hid): + push_operation_stack(f"删除房源ID:{hid} 地址:{addr}") + except: + print("ID必须是整数") + + elif choice == "3": + try: + hid = int(input("输入要修改房源ID:")) + edit = {} + a = input("新地址(回车不修改):") + if a: edit["address"] = a + p = input("新租金(回车不修改):") + if p: edit["price"] = float(p) + ar = input("新面积(回车不修改):") + if ar: edit["area"] = float(ar) + t = input("新户型(回车不修改):") + if t: edit["house_type"] = t + if edit: + if update_house(hid, edit): + push_operation_stack(f"修改房源ID:{hid} 变更:{edit}") + else: + print("未填写任何修改内容") + except: + print("输入格式错误") + + elif choice == "4": + print("1-ID 2-地址 3-租金 4-户型") + sel = input("选择查询类型:") + map_dic = {"1":"id","2":"address","3":"price","4":"house_type"} + if sel not in map_dic: + print("选择无效") + continue + val = input("输入查询值:") + res_list = query_house(map_dic[sel], val) + if not res_list: + print("未找到房源") + continue + for h in res_list: + print(f"ID:{h['id']} 地址:{h['address']} 租金:{h['price']}") + if map_dic[sel] == "id": + push_browse_stack(h["id"]) + + elif choice == "5": + op_record_menu() + elif choice == "6": + browse_history_menu() + + #3.0 + elif choice == "7": + # 测试地址字符串解析 + full_addr = input("输入完整地址(如:四川省德阳市什邡市XX小区):") + res = parse_address_string(full_addr) + print("解析结果:", res) + + elif choice == "8": + # 按区域关键词模糊查询 + keyword = input("输入区域关键词(如:什邡、德阳):") + res_list = fuzzy_query_by_district(keyword) + if not res_list: + print("未找到该区域房源") + else: + for h in res_list: + print(f"ID:{h['id']} 地址:{h['address']}") + + elif choice == "9": + # 初始化小区邻接矩阵 + community_input = input("输入所有小区名称,用英文逗号分隔:") + community_list = community_input.split(",") + init_community_matrix(community_list) + + elif choice == "10": + # 更新两个小区距离 + c1 = input("输入小区A名称:") + c2 = input("输入小区B名称:") + try: + dis = float(input("输入两小区距离:")) + update_matrix_distance(c1, c2, dis) + except: + print("距离必须是数字") + + elif choice == "11": + print("系统退出成功!") + break + else: + print("请输入有效编号") + +if __name__ == "__main__": + main() \ No newline at end of file