向大家问好。我正在为我的 DSA 课程开发一个图书馆管理应用程序。我们使用 Borland Graphics.h 库来绘制用户界面(从这张图片here可以看出)。如图所示,左列包含书名结构列表,又名
DauSach
,代码如下:
struct DauSach {
char ISBN[MAX_ISBN + 1];
char tensach[MAX_TENSACH + 1];
int sotrang;
char tacgia[MAX_TACGIA + 1];
int nxb;
char theloai[MAX_THELOAI + 1];
PtrSach* First = nullptr;
int soluotmuon;
int soluong;
DauSach() {
}
DauSach(char* isbn, char* ten, int st, char* tg, int xb, char* tl) {
strcpy(ISBN, isbn);
strcpy(tensach, ten);
sotrang = st;
strcpy(tacgia, tg);
nxb = xb;
strcpy(theloai, tl);
First = nullptr;
soluong = 0;
soluotmuon = 0;
}
};
struct DS_DauSach {
int n;
DauSach* nodes[MAX_SIZE_DAUSACH];
DS_DauSach() {
n = 0;
}
~DS_DauSach() {
while (n) {
DeleteAllPtrSach(nodes[n - 1]->First);
delete nodes[--n];
}
}
};
内部
DauSach
是书的单链接列表,又名 Sach
,其结构如下:
struct Sach {
char MASACH[MAX_MASACH + 1];
int trangthai;
char vitri[MAX_VITRI + 1];
Sach() {
}
Sach(char ms[MAX_MASACH + 1], int tt, char vt[MAX_VITRI + 1]) {
strcpy(MASACH, ms);
trangthai = tt;
strcpy(vitri, vt);
}
};
// NODE Sach - DSLK don
struct PtrSach {
Sach sach;
PtrSach* next;
};
从上图中可以看到,右栏是显示
Sach
列表的位置。每本书都有删除功能,假设你有一本名为“TEST”的书,“TEST”书的列表是TEST-0
TEST-1
TEST-2
。我想删除这本书TEST-1
,应该只有TEST-0
和TEST-1
。删除书籍的步骤如下。
首先,我用这段代码获取当前书籍的节点。
PtrSach* nodeSelect = GetPtrSach(DSDS.nodes[curDauSach]->First, 10 * (curPageSach - 1) + curSach);
PtrSach* GetPtrSach(PtrSach* First, int position) {
PtrSach* node = First;
for (int i = 0; node != nullptr; node = node->next) {
if (i == position) {
return node;
}
++i;
}
return nullptr; // Return nullptr if position is out of bounds
}
然后,在我有了节点之后,我通过选择结构体的当前名称
Sach
来删除这本书,假设它当前是TEST-1
。
XoaPtrSachTheoMaSach(nodeSelect, sach.MASACH);
void XoaPtrSachTheoMaSach(PtrSach*& head, char* targetMASACH) {
if (head == nullptr) return; // Empty list
while (head != nullptr && strcmp(head->sach.MASACH, targetMASACH) == 0) {
PtrSach* tmp = head;
head = head->next;
delete tmp;
}
if (head == nullptr) return;
PtrSach* current = head;
while (current->next != nullptr) {
if (strcmp(current->next->sach.MASACH, targetMASACH) == 0) {
PtrSach* tmp = current->next;
current->next = current->next->next;
delete tmp;
}
else {
current = current->next;
}
}
}
删除后,我只是用此代码再次将当前书籍列表打印到右侧列。
void DrawDanhMucSach() {
... // these previous part can be ignored
PtrSach* node = GetPtrSach(DSDS.nodes[curDauSach]->First, 10 * (curPageSach - 1));
for (int i = 0; node != nullptr && i < 10; node = node->next) {
DrawItemSach(node->sach, i++);
}
}
我遇到的问题是,在外部测试时(我可以保证)函数
XoaPtrSachTheoMaSach
按预期工作,但是在程序中包含代码后,它无法正确打印。相反,TEST-1
的节点似乎没有完全删除,因为其中仍然留有垃圾值(怀疑是 nullptr 或其他东西?我不知道)。 这是我的意思的图片。问题是,如果删除函数起作用,则应删除该节点,并打印下一个节点,或者如果删除的节点已经是最后一个节点,则应将其分配给 nullptr 并停止打印。有谁知道或解决这种情况首先是如何发生的?
注意:我们不允许使用标准库,但是内部有
string
库,只能与 strcpy
函数一起使用或在 char[]
之间进行比较。
这个循环不正确
PtrSach* current = head;
while (current->next != nullptr) {
if (strcmp(current->next->sach.MASACH, targetMASACH) == 0) {
PtrSach* tmp = current->next;
current->next = current->next->next;
delete tmp;
}
else {
current = current->next;
}
}
删除
current->next
时,必须使current
指向current->next
之后的节点。换句话说,代码应该是
PtrSach* current = head;
while (current->next != nullptr) {
if (strcmp(current->next->sach.MASACH, targetMASACH) == 0) {
PtrSach* tmp = current->next;
current = current->next->next; // CHANGE HERE
delete tmp;
}
else {
current = current->next;
}
}