目录
1. 实验内容及上机实验所用平台
1.1 实验内容
有一个非空双链表 L
,设计一个算法删除第一个值为 x
的节点。
1.2 设计思路
创建好双链表后,只要从首结点开始查找值 x
,找到后将值 x
的前驱结点指针指向值 x
的后继结点,将值 x
的后继结点指针指向值 x
的前驱结点即可。
1.3 实验平台软件
Dev-C++.
2. 数据结构
非空双链表,有指向前驱结点的 prior
指针和指向后继结点的 next
指针。
3. 设计描述与分析
3.1 伪代码
输入:数组 num
和要删除的值 x
。
输出:删除值 x
后新的双链表。
// 利用数组num创建双链表
// 生成结点*p ← (dhead → next)
while p != NULL and p 指向的值 !=x
p ← (p → next)
end while
if p != NULL
(p → prior → next) ← (p → next)
if p → next != NULL
(p → next → prior) ← (p → prior)
end if
end if
3.2 流程图
3.3 主要代码段
void DelFx(int x) {
DLinkNode *p = dhead -> next; // p 指向首结点
while (p != NULL && p -> val != x) p = p -> next; // 跳过值不是x的结点
if (p != NULL) { // 找到值是 x 的结点
p -> prior -> next = p -> next;
if (p -> next != NULL) p -> next -> prior = p -> prior; // 删除结点 p
delete p; // 释放空间
}
}
3.4 源代码
需要先在源代码目录下新建 in.txt
文件,在此文件下输入要测试的数据。
注:为了少写点代码,这里用到了 C++
的关键字 new
。
#include <iostream>
using namespace std;
struct DLinkNode // 双链表结点类型
{
int val; // 存放数据元素
DLinkNode *next; // 指向后继结点的指针
DLinkNode *prior; // 指向前驱结点的指针
DLinkNode():next(NULL),prior(NULL) {} // 构造函数
DLinkNode(int x):val(x),next(NULL),prior(NULL) {} // 重载构造函数
};
class DLinkList{
public:
DLinkNode *dhead; // 双链表头结点
DLinkList() // 构造函数,创建一个空双链表
{
dhead = new DLinkNode();
}
void CreateListR(int a[], int n) // 尾插法建立双链表
{
DLinkNode *s, *r;
r = dhead; // r始终指向尾结点,开始时指向头结点
for (int i = 0; i < n; i++) // 循环建立数据结点
{
s = new DLinkNode(a[i]); // 创建数据结点s
r -> next = s; // 将s结点插入r结点之后
s -> prior = r;
r = s;
}
r -> next = NULL; // 将尾结点的 next域置为 NULL
}
void DelFx(int x) {
DLinkNode *p = dhead -> next; // p 指向首结点
while (p != NULL && p -> val != x) p = p -> next; // 跳过值不是 x 的结点
if (p != NULL) { // 找到值是 x 的结点
p -> prior -> next = p -> next;
if (p -> next != NULL) p -> next -> prior = p -> prior; // 删除结点 p
delete p; // 释放空间
}
}
void DispList() // 输出双链表所有结点值
{
DLinkNode *p;
p = dhead -> next; // p指向开始结点
while (p != NULL) // p不为 NULL,输出 p结点的 data域
{
cout << p -> val << " ";
p = p -> next; // p移向下一个结点
}
cout << endl;
}
};
int main() {
cout << "\t\t第5题 - 双链表结点删除\n\n";
cout << "---------------------------------------------------\n\n";
freopen("in.txt", "r", stdin);
int num[1001] = {0}, cnt = 0, x;
while (cin >> num[cnt++]); // 从 in.txt 中读取所有数据
cnt--; // 因为 在读取数据时 cnt++ 多运行了一次,所以减 1 得到所有数据的长度
x = num[cnt-1]; // 读取数据中的最后一个数据是 target,取出来
cnt--; // 得到数组长度
cout << "样例输入:\n";
for (int i = 0; i < cnt; i++) cout << num[i] << " ";
cout << "\n" << x << "\n\n样例输出:\n";
DLinkList L;
L.CreateListR(num, cnt); // 创建循环单链表
L.DelFx(x);
L.DispList();
cout << "\n\n";
freopen("CON", "r", stdin); // 为了可直接查看exe可执行文件,需要将权限返回键盘
system("pause");
return 0;
}
4. 调试过程
-
测试1
a) 测试数据用例:2 7 11 15 7 2
b) 测试数据用例1的特点:删除结点出现在表首。
c) 测试结果:
-
测试2
a) 测试数据用例:2 11 7 15 7 7
b) 测试数据用例2的特点:删除结点出现在表中,且是重复元素。
c) 测试结果:
-
测试3
a) 测试数据用例:2 11 7 15 8 8
b) 测试数据用例3的特点:删除结点出现在表尾。
c) 测试结果:
5. 实验总结
在本次实验中,主要是熟悉创建双链表以及删除值的操作,以及要时刻判断删除指针时它本身以及它的后继是否为空,总体来说没有前面的题目难。