双向链表分页输出函数异常:回退跳页/循环问题求助
双向链表达页输出异常修复方案
问题概述
实现了双向链表的分页输出函数ShowList,每页展示count/2(即5条)数据,末尾不足一页的数据单独处理。当前存在两个异常:
- 翻到末尾后回退会跳过一页
- 按分页大小回退时,会循环到最后一页及末尾数据
修改逻辑后仍存在末尾循环问题,原代码及尝试修改如下:
原代码
void ShowList(hwnd* hwnd){ int id = 0, count = 10, CountElementstInEnd; node* temp; node* head = hwnd->head; node* UpLimit = hwnd->head; node* LwLimit = hwnd->tail; if(!head) return; for(int i = 0; i < count/2 ; i++) UpLimit = UpLimit->next; CountElementstInEnd = hwnd->size % (count/2) - 1; for(int i = 0; i < CountElementstInEnd; i++) LwLimit = LwLimit->prev; temp = LwLimit; char c; do { system("cls"); puts (" ID NAME SEX SPORT BORN GROWTH "); for(int i = 0; i < count/2 ; i++, id++){ ///Output the records at the end (their number may not be a multiple of count/2) if(head == LwLimit){ for(int i = 0; i < CountElementstInEnd; i++, id++){ printf(" %-2.2d %-12.12s %-6.6s %-16.16s %-4.4d %-3.3d \n", id, temp->data->name, temp->data->sex, temp->data->sport, temp->data->born, temp->data->growth); temp = temp->next; } temp = LwLimit; id-=CountElementstInEnd; break; } ///normal output printf(" %-2.2d %-12.12s %-6.6s %-16.16s %-4.4d %-3.3d \n", id, head->data->name, head->data->sex, head->data->sport, head->data->born, head->data->growth); head = head->next; } ///users input 1 - next, 2 - prev while(1){ c = getch(); if (c == 0x31 && (head == LwLimit)){ for(int i = 0; i < count; i++) head = head->prev; id -= count; break; } if (c == 0x31 && (head != UpLimit)){ for(int i = 0; i < count; i++) head = head->prev; id -= count; break; } else if(c == 0x32 || c == 27) break; } } while(c != 27); }
尝试的修改代码
if (c == 0x31 && (head == hwnd->tail)){ head = head->prev->prev; break; }
问题根源
- 边界计算错误:
CountElementstInEnd = hwnd->size % (count/2) - 1未考虑整除场景,余数为0时会得到负数,导致LwLimit定位错误。 - 翻页步长错误:翻页时移动了
count(10个)节点,但每页仅展示5个,步长不匹配导致跳页。 - 边界判断混乱:
UpLimit/LwLimit的定位逻辑不清晰,无法正确识别分页边界状态。 - ID计数不同步:ID未根据当前页起始位置重新计算,导致翻页后ID混乱。
修复后的完整代码
#include <conio.h> // 确保getch()可用 // 辅助函数:获取节点在链表中的索引(从0开始) int get_node_index(hwnd* hwnd, node* target){ int index = 0; node* temp = hwnd->head; while(temp != target){ index++; temp = temp->next; } return index; } void ShowList(hwnd* hwnd){ const int PAGE_SIZE = 5; // 每页固定展示5条数据 int current_id; node* current_page_start = hwnd->head; char c; if(!current_page_start) return; // 预计算分页关键参数 int total_elements = hwnd->size; int total_pages = (total_elements + PAGE_SIZE - 1) / PAGE_SIZE; // 向上取整计算总页数 int last_page_count = total_elements % PAGE_SIZE; if(last_page_count == 0) last_page_count = PAGE_SIZE; // 整除时最后一页也是PAGE_SIZE条 do { system("cls"); puts(" ID NAME SEX SPORT BORN GROWTH "); // 计算当前页的起始ID(从1开始) current_id = get_node_index(hwnd, current_page_start) + 1; node* temp = current_page_start; // 判断当前是否为最后一页,确定要展示的条数 int current_page_num = (get_node_index(hwnd, current_page_start) / PAGE_SIZE) + 1; int display_count = (current_page_num == total_pages) ? last_page_count : PAGE_SIZE; // 输出当前页数据 for(int i = 0; i < display_count; i++, current_id++){ printf(" %-2.2d %-12.12s %-6.6s %-16.16s %-4.4d %-3.3d \n", current_id, temp->data->name, temp->data->sex, temp->data->sport, temp->data->born, temp->data->growth); temp = temp->next; } // 处理用户输入:1=下一页,2=上一页,ESC=退出 while(1){ c = getch(); if(c == '1'){ // 下一页:仅当前页不是最后一页时允许翻页 if(current_page_num < total_pages){ // 移动到下一页起始位置 for(int i = 0; i < PAGE_SIZE; i++){ current_page_start = current_page_start->next; } } break; } else if(c == '2'){ // 上一页:仅当前页不是第一页时允许翻页 if(current_page_num > 1){ // 回退到上一页起始位置 for(int i = 0; i < PAGE_SIZE; i++){ current_page_start = current_page_start->prev; } } break; } else if(c == 27){ // ESC键ASCII码 break; } } } while(c != 27); }
关键修改说明
- 固定分页参数:用常量
PAGE_SIZE替代count/2,避免重复计算,代码更易维护。 - 正确计算分页边界:通过向上取整计算总页数,处理整除场景下的最后一页条数。
- 索引化分页定位:新增
get_node_index辅助函数,准确计算当前页的页码和起始ID,解决ID混乱问题。 - 清晰的翻页逻辑:
- 下一页:仅当不是最后一页时,向前移动
PAGE_SIZE个节点 - 上一页:仅当不是第一页时,向后移动
PAGE_SIZE个节点 - 彻底避免了边界循环和跳页问题
- 下一页:仅当不是最后一页时,向前移动
- 简化输出逻辑:通过页码判断是否为最后一页,直接输出对应条数的数据,删除了原代码中混乱的
LwLimit/UpLimit判断。
内容的提问来源于stack exchange,提问作者cvetochek
相关产品推荐
相关产品推荐

