
简介本资源是面向高校计算机专业本科生的数据结构课程设计实践项目聚焦火车管理系统这一典型应用场景帮助学习者将链表、数组、栈、队列、二叉搜索树、哈希表及图等核心数据结构知识落地为可运行系统。压缩包共3个文件1个C源码、1个可执行程序、1份Word文档总大小455KB轻量实用C文件实现核心逻辑exe支持直接演示功能docx文档详述设计思路、数据结构选型依据、算法分析与扩展建议。已有618人学习下载适合课程设计参考、期末项目复盘或数据结构综合实训。读者可完整掌握从需求建模、结构选型、代码实现到文档撰写的全流程尤其深入理解不同数据结构在车次管理、座位分配、购票排队、快速查询等子模块中的适配逻辑与性能权衡。1. 用链表、栈、队列和二叉排序树搭一套可查、可删、可调度的火车管理系统你刚写完《数据结构》课设选题表填了“火车管理系统”——老师没说必须用图形界面也没要求对接真实铁路调度系统。但交作业那天隔壁组用纯 C 写了个带菜单、能增删车次、按站名查车、还能模拟发车顺序的控制台程序老师当场多给了 5 分。这不是炫技而是把线性表、栈、队列、树四大核心结构全串起来了车次信息用单链表动态管理始发站到终点站的经停序列用双向链表维护候补购票队列用循环队列实现公平排队而按车次号快速检索、插入、删除则靠二叉排序树BST支撑 O(log n) 查询。本篇不讲抽象理论只带你用 C 语言从零写出一个可编译、可调试、可扩展的课程设计级火车管理系统——所有结构体定义、内存管理逻辑、关键算法如 BST 中序遍历生成时刻表、边界处理如空链表头结点判空、队列满/空标志全部展开参数命名直白注释写在代码行内连malloc失败怎么回滚都标清楚。适合大二刚学完严蔚敏《数据结构C语言版》第2章到第6章的同学直接抄作业也够大三面试前刷“数据结构高频核心知识点面试”时复盘链表与树的协同设计。2. 用带头结点单链表管理车次主表支持动态增删与按条件遍历火车管理系统最基础的数据是车次本身G101、D305、K987 这类唯一标识加上始发站、终点站、发车时间、余票数等字段。这些记录数量不确定、增删频繁用数组会浪费空间或触发频繁 realloc用静态链表又失去指针灵活性。带头结点的单链表是课程设计中最稳妥的选择——头结点不存实际数据统一简化插入/删除逻辑避免对首结点特殊处理完全对应严蔚敏教材中“线性表的链式表示和实现”一节的规范写法。2.1 定义车次结构体与链表结点明确内存布局#include stdio.h #include stdlib.h #include string.h #define MAX_STATION_LEN 20 #define MAX_TIME_LEN 10 // 车次基本信息结构体 typedef struct TrainNode { char trainNo[10]; // 车次号如G101 char startStation[MAX_STATION_LEN]; char endStation[MAX_STATION_LEN]; char depTime[MAX_TIME_LEN]; // 发车时间格式08:30 int remainingTickets; // 余票数 struct TrainNode* next; // 指向下一车次 } TrainNode; // 链表头结点不存数据 typedef struct { TrainNode* head; } TrainList;提示trainNo字段长度设为 10 是因国内高铁/动车号最长为 G4位数字如G1001普快为 K4位如K1234留足缓冲remainingTickets用int而非short避免后续扩展座位类型硬座/二等座时溢出。2.2 初始化链表并插入首条车次验证头结点有效性// 初始化空链表分配头结点内存next置NULL TrainList* initTrainList() { TrainList* list (TrainList*)malloc(sizeof(TrainList)); if (!list) { printf(初始化链表失败内存分配失败\n); return NULL; } list-head (TrainNode*)malloc(sizeof(TrainNode)); // 头结点 if (!list-head) { printf(初始化链表失败头结点内存分配失败\n); free(list); return NULL; } list-head-next NULL; // 头结点next指向NULL表示空表 return list; } // 在链表尾部插入新列车保持按录入顺序排列 int insertTrainAtTail(TrainList* list, const char* trainNo, const char* start, const char* end, const char* time, int tickets) { if (!list || !list-head) return -1; // 创建新结点 TrainNode* newNode (TrainNode*)malloc(sizeof(TrainNode)); if (!newNode) { printf(插入失败新结点内存分配失败\n); return -1; } // 复制字符串防止传入栈变量地址失效 strncpy(newNode-trainNo, trainNo, sizeof(newNode-trainNo)-1); newNode-trainNo[sizeof(newNode-trainNo)-1] \0; strncpy(newNode-startStation, start, sizeof(newNode-startStation)-1); newNode-startStation[sizeof(newNode-startStation)-1] \0; strncpy(newNode-endStation, end, sizeof(newNode-endStation)-1); newNode-endStation[sizeof(newNode-endStation)-1] \0; strncpy(newNode-depTime, time, sizeof(newNode-depTime)-1); newNode-depTime[sizeof(newNode-depTime)-1] \0; newNode-remainingTickets tickets; newNode-next NULL; // 找到尾结点最后一个next为NULL的结点 TrainNode* p list-head; while (p-next ! NULL) { p p-next; } p-next newNode; // 尾插 return 0; }参数说明与调用示例initTrainList()返回TrainList*指针后续所有操作均基于此指针insertTrainAtTail()第二个参数trainNo是 C 字符串函数内部用strncpy安全复制避免strcpy缓冲区溢出调用示例insertTrainAtTail(myList, G101, 北京南, 上海虹桥, 08:30, 120);关键细节头结点list-head的next初始为NULL代表空链表插入时遍历到p-next NULL才停止确保新结点挂在最后。2.3 按车次号查找并返回结点地址支撑后续修改与删除// 根据车次号查找结点返回指向该结点的指针用于修改/删除 TrainNode* findTrainByNo(TrainList* list, const char* trainNo) { if (!list || !list-head || !trainNo) return NULL; TrainNode* p list-head-next; // 从第一个实际结点开始 while (p ! NULL) { if (strcmp(p-trainNo, trainNo) 0) { return p; // 找到返回结点地址 } p p-next; } return NULL; // 未找到 } // 删除指定车次需先找到前驱结点 int deleteTrainByNo(TrainList* list, const char* trainNo) { if (!list || !list-head || !trainNo) return -1; TrainNode* prev list-head; // 前驱结点初始为头结点 TrainNode* curr list-head-next; // 当前结点 while (curr ! NULL) { if (strcmp(curr-trainNo, trainNo) 0) { prev-next curr-next; // 跳过curr free(curr); // 释放内存 return 0; // 成功 } prev curr; curr curr-next; } return -1; // 未找到 }注意findTrainByNo()返回的是TrainNode*不是TrainList*这样调用方能直接访问-remainingTickets字段修改余票deleteTrainByNo()必须维护prev指针因为单链表无法反向找前驱——这是严蔚敏教材强调的“删除操作需遍历找前驱”的典型场景。2.4 遍历打印所有车次验证链表状态与调试技巧// 打印全部车次信息用于调试和菜单显示 void printAllTrains(TrainList* list) { if (!list || !list-head) { printf(车次列表为空\n); return; } TrainNode* p list-head-next; if (p NULL) { printf(暂无车次信息\n); return; } printf(\n 当前车次列表 \n); printf(%-10s %-12s %-12s %-10s %-10s\n, 车次号, 始发站, 终点站, 发车时间, 余票); printf(--------------------------------------------------\n); while (p ! NULL) { printf(%-10s %-12s %-12s %-10s %-10d\n, p-trainNo, p-startStation, p-endStation, p-depTime, p-remainingTickets); p p-next; } printf(--------------------------------------------------\n); }输出效果与调试价值 当前车次列表 车次号 始发站 终点站 发车时间 余票 -------------------------------------------------- G101 北京南 上海虹桥 08:30 120 D305 广州南 长沙南 10:15 85 K987 成都东 重庆北 14:20 42 --------------------------------------------------表头对齐用%-10s等格式化符确保中文字符不乱码空链表时输出“暂无车次信息”避免p-next解引用崩溃此函数是课程设计调试核心——每次增删后调用它立刻验证链表是否断裂、数据是否错位。3. 用双向链表管理单趟列车的经停站序列支持任意位置增删与逆序查询车次 G101 不只是“北京南→上海虹桥”它实际停靠北京南、天津西、济南西、南京南、上海虹桥共5站。若用单链表存储这些站点从上海虹桥反查上一站南京南需从头遍历O(n) 效率低而课程设计常要求“查询某站之后所有停靠站”或“在第3站插入临时停靠点”。双向链表天然支持前后双向遍历且插入/删除任意位置只需修改相邻3个结点指针严蔚敏教材第2章明确将其列为“线性表链式存储的进阶实现”。3.1 定义经停站结点与双向链表结构区分车次主表与站点子表// 经停站结点属于某趟车次的子结构 typedef struct StationNode { char stationName[MAX_STATION_LEN]; int order; // 停靠顺序号从1开始 struct StationNode* prev; // 指向前一站 struct StationNode* next; // 指向后一站 } StationNode; // 单趟车次的经停站双向链表嵌入在TrainNode中 // 注意TrainNode结构体需扩展此处为独立定义便于理解 typedef struct { StationNode* head; // 头结点不存数据 StationNode* tail; // 尾结点不存数据加速尾插 } StationList;关键设计理由StationNode中order字段冗余但必要——当用户要求“显示G101第3站之后所有站点”时可直接比对order 3避免遍历计数tail指针非必需但课程设计中尾插高频新增停靠站通常加在末尾加tail可将尾插从 O(n) 降为 O(1)符合“优化实践”要求。3.2 构建双向链表并插入经停站验证指针双向连通性// 初始化空双向链表头尾结点 StationList* initStationList() { StationList* list (StationList*)malloc(sizeof(StationList)); if (!list) return NULL; list-head (StationNode*)malloc(sizeof(StationNode)); list-tail (StationNode*)malloc(sizeof(StationNode)); if (!list-head || !list-tail) { if (list-head) free(list-head); if (list-tail) free(list-tail); free(list); return NULL; } list-head-next list-tail; list-head-prev NULL; list-tail-prev list-head; list-tail-next NULL; return list; } // 在双向链表尾部插入新站点按停靠顺序 int insertStationAtTail(StationList* list, const char* station, int order) { if (!list || !list-head || !list-tail || !station) return -1; StationNode* newNode (StationNode*)malloc(sizeof(StationNode)); if (!newNode) return -1; strncpy(newNode-stationName, station, sizeof(newNode-stationName)-1); newNode-stationName[sizeof(newNode-stationName)-1] \0; newNode-order order; // 插入到 tail 前面即链表末尾 newNode-prev list-tail-prev; newNode-next list-tail; list-tail-prev-next newNode; list-tail-prev newNode; return 0; }指针操作逻辑详解初始化时head-next tailtail-prev head形成head ↔ tail的空链插入时newNode的prev指向tail-prev原尾结点前一个next指向tail然后更新原尾结点前驱的next指向newNode再更新tail-prev指向newNode验证方法插入后检查newNode-prev-next newNode且newNode-next-prev newNode双向连通即正确。3.3 按顺序号查找站点并支持逆序遍历覆盖课程设计高频需求// 根据顺序号查找站点如查第3站 StationNode* findStationByOrder(StationList* list, int order) { if (!list || !list-head || !list-tail) return NULL; StationNode* p list-head-next; // 第一个实际站点 while (p ! list-tail) { if (p-order order) return p; p p-next; } return NULL; } // 从终点站反向打印所有经停站逆序遍历 void printStationsReverse(StationList* list) { if (!list || !list-head || !list-tail) return; StationNode* p list-tail-prev; // 从最后一个实际站点开始 printf(逆序停靠站); while (p ! list-head) { printf(%s , p-stationName); p p-prev; } printf(\n); }课程设计典型应用场景用户输入“G101 第3站”调用findStationByOrder(stationListG101, 3)得到“济南西”用户选择“查看返程时刻”调用printStationsReverse()输出 “上海虹桥 南京南 济南西 天津西 北京南”边界处理p ! list-head作为循环终止条件避免访问头结点数据头结点无意义。3.4 将经停站链表嵌入车次主表实现数据结构嵌套管理// 修改 TrainNode 结构体增加经停站链表指针 // 实际编码中需在头文件或结构体定义处同步更新 typedef struct TrainNode { char trainNo[10]; char startStation[MAX_STATION_LEN]; char endStation[MAX_STATION_LEN]; char depTime[MAX_TIME_LEN]; int remainingTickets; StationList* stations; // 关键每个车次拥有自己的双向链表 struct TrainNode* next; } TrainNode; // 创建车次时同时初始化其经停站链表 TrainNode* createTrainWithStations(const char* trainNo, const char* start, const char* end, const char* time, int tickets) { TrainNode* train (TrainNode*)malloc(sizeof(TrainNode)); if (!train) return NULL; strncpy(train-trainNo, trainNo, sizeof(train-trainNo)-1); train-trainNo[sizeof(train-trainNo)-1] \0; strncpy(train-startStation, start, sizeof(train-startStation)-1); train-startStation[sizeof(train-startStation)-1] \0; strncpy(train-endStation, end, sizeof(train-endStation)-1); train-endStation[sizeof(train-endStation)-1] \0; strncpy(train-depTime, time, sizeof(train-depTime)-1); train-depTime[sizeof(train-depTime)-1] \0; train-remainingTickets tickets; train-stations initStationList(); // 初始化子链表 train-next NULL; return train; }设计深意TrainNode中stations是指针而非结构体实体避免内存浪费createTrainWithStations()封装了主表与子表的联动创建体现“数据结构组合应用”思想——这正是《数据结构课程设计》区别于单个实验的核心。4. 用循环队列实现候补购票队列保证FIFO公平性与内存高效利用当 G101 余票为 0 时用户可加入候补队列。课程设计要求“先到先得”即严格 FIFO先进先出。若用普通数组模拟队列删除首元素需移动后续所有元素O(n) 效率低用链表则内存碎片化。循环队列用固定大小数组 front/rear双指针实现插入删除均为 O(1)且严蔚敏教材第3章“栈和队列”明确将其列为“队列的顺序表示”标准解法。本节实现容量为 100 的循环队列支持满/空判断、入队、出队、查看队首。4.1 定义循环队列结构体与关键宏规避下标越界风险#define MAX_WAITING 100 // 候补队列最大容量 typedef struct { char trainNo[10]; // 关联车次号 char passengerName[MAX_STATION_LEN]; // 乘客姓名 int waitNumber; // 排队序号从1开始 } WaitingItem; typedef struct { WaitingItem data[MAX_WAITING]; int front; // 队首下标初始为0 int rear; // 队尾下标初始为0 int size; // 当前元素个数用于判空/判满 } WaitingQueue;为什么用size而非(rear1)%MAX_WAITING front判满后者需牺牲一个存储单元满时rear指向front-1易引发初学者混淆用size字段更直观且size可直接用于统计当前候补人数符合课程设计“功能实用”原则。4.2 初始化队列并实现入队/出队包含完整错误处理// 初始化空队列 WaitingQueue* initWaitingQueue() { WaitingQueue* q (WaitingQueue*)malloc(sizeof(WaitingQueue)); if (!q) return NULL; q-front 0; q-rear 0; q-size 0; return q; } // 入队添加候补乘客 int enqueue(WaitingQueue* q, const char* trainNo, const char* name) { if (!q || q-size MAX_WAITING) return -1; // 队满 // 计算插入位置rear 当前指向下一个空位 int index q-rear; q-rear (q-rear 1) % MAX_WAITING; // 复制数据 strncpy(q-data[index].trainNo, trainNo, sizeof(q-data[index].trainNo)-1); q-data[index].trainNo[sizeof(q-data[index].trainNo)-1] \0; strncpy(q-data[index].passengerName, name, sizeof(q-data[index].passengerName)-1); q-data[index].passengerName[sizeof(q-data[index].passengerName)-1] \0; q-data[index].waitNumber q-size 1; // 序号从1开始 q-size; return 0; } // 出队首位乘客购票成功返回其信息 int dequeue(WaitingQueue* q, WaitingItem* item) { if (!q || q-size 0) return -1; // 队空 *item q-data[q-front]; // 复制数据 q-front (q-front 1) % MAX_WAITING; q-size--; return 0; }关键参数与行为说明enqueue()中q-rear指向下一个待插入位置插入后立即更新rear符合教材“rear 指向队尾后一位置”的约定dequeue()返回WaitingItem*类型的item调用方需传入已分配内存的变量地址避免返回局部变量waitNumber q-size 1确保序号严格递增即使中间有出队操作也不跳号。4.3 查询队列状态与打印候补列表支撑课程设计交互菜单// 获取队列当前长度 int getQueueSize(WaitingQueue* q) { return q ? q-size : 0; } // 打印全部候补信息按排队顺序 void printWaitingList(WaitingQueue* q) { if (!q || q-size 0) { printf(候补队列为空\n); return; } printf(\n 候补购票队列共%d人\n, q-size); printf(%-10s %-15s %-10s\n, 车次号, 乘客姓名, 排队序号); printf(----------------------------------------\n); int i q-front; for (int count 0; count q-size; count) { printf(%-10s %-15s %-10d\n, q-data[i].trainNo, q-data[i].passengerName, q-data[i].waitNumber); i (i 1) % MAX_WAITING; // 循环下标 } printf(----------------------------------------\n); }实际运行效果 候补购票队列共3人 车次号 乘客姓名 排队序号 ---------------------------------------- G101 张三 1 G101 李四 2 D305 王五 3 ----------------------------------------循环遍历用i (i 1) % MAX_WAITING确保下标自动绕回getQueueSize()直接返回q-sizeO(1) 时间复杂度避免遍历计数。5. 用二叉排序树BST索引车次号实现O(log n)快速检索与动态维护当系统车次超过 50 条时链表遍历查找车次号平均需 25 次比较效率低下。课程设计升级要求“秒级响应”必须引入树结构。二叉排序树BST是严蔚敏教材第6章“树和二叉树”的核心内容左子树所有结点值小于根右子树所有结点值大于根中序遍历得有序序列。本节实现基于车次号字符串的 BST支持插入、查找、中序遍历生成按字母序排列的车次表并解决字符串比较的陷阱。5.1 定义BST结点与树结构明确字符串比较规则// BST结点以车次号为关键字 typedef struct BSTNode { char trainNo[10]; TrainNode* trainPtr; // 指向主链表中的实际车次结点非复制数据 struct BSTNode* left; struct BSTNode* right; } BSTNode; typedef struct { BSTNode* root; } TrainBST;为什么trainPtr存指针而非复制数据避免内存浪费和数据不一致主链表中车次余票修改后BST 中trainPtr-remainingTickets自动同步若复制数据需双写维护违反“单一数据源”原则。5.2 实现BST插入与递归查找处理字符串比较边界// 字符串比较辅助函数封装 strcmp避免空指针 int compareTrainNo(const char* a, const char* b) { if (!a !b) return 0; if (!a) return -1; if (!b) return 1; return strcmp(a, b); } // 递归插入车次号到BST BSTNode* insertBST(BSTNode* root, const char* trainNo, TrainNode* trainPtr) { if (root NULL) { BSTNode* newNode (BSTNode*)malloc(sizeof(BSTNode)); if (!newNode) return NULL; strncpy(newNode-trainNo, trainNo, sizeof(newNode-trainNo)-1); newNode-trainNo[sizeof(newNode-trainNo)-1] \0; newNode-trainPtr trainPtr; newNode-left newNode-right NULL; return newNode; } int cmp compareTrainNo(trainNo, root-trainNo); if (cmp 0) { root-left insertBST(root-left, trainNo, trainPtr); } else if (cmp 0) { root-right insertBST(root-right, trainNo, trainPtr); } // 若相等车次号已存在不插入返回原root return root; } // 非递归查找更符合课程设计对“算法实现能力”的考察 TrainNode* searchBST(TrainBST* tree, const char* trainNo) { if (!tree || !tree-root || !trainNo) return NULL; BSTNode* p tree-root; while (p ! NULL) { int cmp compareTrainNo(trainNo, p-trainNo); if (cmp 0) { return p-trainPtr; // 找到返回主链表结点 } else if (cmp 0) { p p-left; } else { p p-right; } } return NULL; // 未找到 }字符串比较陷阱与解决方案strcmp(NULL, G101)会崩溃故封装compareTrainNo()做空指针防护insertBST()用递归代码简洁searchBST()用迭代避免深递归栈溢出车次超百条时安全插入时cmp 0不处理天然去重——车次号必须唯一符合现实约束。5.3 中序遍历生成有序车次表用于课程设计“按车次号排序显示”功能// 中序遍历回调函数类型 typedef void (*BSTVisitFunc)(TrainNode*); // 中序遍历BST对每个结点调用visitFunc void inorderBST(BSTNode* root, BSTVisitFunc visitFunc) { if (root NULL) return; inorderBST(root-left, visitFunc); if (visitFunc root-trainPtr) { visitFunc(root-trainPtr); // 传入主链表结点 } inorderBST(root-right, visitFunc); } // 打印BST中所有车次按车次号字典序 void printBSTInorder(TrainBST* tree) { if (!tree || !tree-root) { printf(BST为空\n); return; } printf(\n 按车次号排序的车次列表BST中序遍历\n); printf(%-10s %-12s %-12s %-10s %-10s\n, 车次号, 始发站, 终点站, 发车时间, 余票); printf(--------------------------------------------------\n); // 匿名函数式回调用lambda风格C99支持 inorderBST(tree-root, [](TrainNode* t) { printf(%-10s %-12s %-12s %-10s %-10d\n, t-trainNo, t-startStation, t-endStation, t-depTime, t-remainingTickets); }); printf(--------------------------------------------------\n); }注意C 标准不支持 lambda此处用函数指针模拟实际编码中需定义独立函数如void printTrainInfo(TrainNode* t)再传入inorderBST(tree-root, printTrainInfo)。5.4 将BST集成到主系统演示一次完整的“查车次”流程// 主系统结构体整合所有数据结构 typedef struct { TrainList* trainList; // 主链表 TrainBST* trainBST; // BST索引 WaitingQueue* waitQ; // 候补队列 } TrainSystem; // 初始化完整系统 TrainSystem* initTrainSystem() { TrainSystem* sys (TrainSystem*)malloc(sizeof(TrainSystem)); if (!sys) return NULL; sys-trainList initTrainList(); sys-trainBST (TrainBST*)malloc(sizeof(TrainBST)); if (!sys-trainList || !sys-trainBST) { if (sys-trainList) free(sys-trainList); if (sys-trainBST) free(sys-trainBST); free(sys); return NULL; } sys-trainBST-root NULL; sys-waitQ initWaitingQueue(); return sys; } // 添加车次时同步更新链表与BST int addTrainToSystem(TrainSystem* sys, const char* trainNo, const char* start, const char* end, const char* time, int tickets) { if (!sys) return -1; // 1. 插入主链表 TrainNode* trainNode createTrainWithStations( trainNo, start, end, time, tickets); if (!trainNode) return -1; if (insertTrainAtTail(sys-trainList, trainNo, start, end, time, tickets) ! 0) { free(trainNode); return -1; } // 2. 插入BST传入主链表中该结点的地址 TrainNode* found findTrainByNo(sys-trainList, trainNo); if (found) { sys-trainBST-root insertBST(sys-trainBST-root, trainNo, found); } return 0; } // 示例用户输入G101系统秒级返回结果 void demoSearch(TrainSystem* sys) { TrainNode* result searchBST(sys-trainBST, G101); if (result) { printf(查到车次%s始发%s终点%s余票%d\n, result-trainNo, result-startStation, result-endStation, result-remainingTickets); } else { printf(未找到车次 G101\n); } }集成逻辑要点addTrainToSystem()先插链表再从链表中findTrainByNo()获取地址插入 BST确保指针有效性demoSearch()展示 BST 的核心价值无论链表多长查找仅需 O(h) 时间h 为树高平衡时 h≈log₂n课程设计加分项在菜单中增加“按车次号排序显示”选项调用printBSTInorder()直接体现 BST 应用价值。6. 用中序遍历栈模拟实现非递归BST遍历解决递归深度限制与内存可视化严蔚敏教材强调“递归程序可改写为非递归”课程设计常要求“用栈模拟递归过程”。BST 中序遍历若用递归树深过大如100层可能栈溢出而用显式栈可精确控制内存并方便调试时观察栈内结点变化。本节给出非递归中序遍历的完整实现包含栈结构定义、压栈/弹栈逻辑、以及如何用该遍历生成可导出的 CSV 格式时刻表——这是课程设计报告中“创新点”和“实用功能”的直接来源。6.1 定义辅助栈结构与初始化匹配BST结点类型// 为BST遍 p a hrefhttps://download.csdn.net/download/weixin_41960515/13711769 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p