【数据结构与算法——C语言】“链表操作与算法”之“双链表结点删除”

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. 测试1
    a) 测试数据用例:

    2 7 11 15 7
    2
    

    b) 测试数据用例1的特点:删除结点出现在表首。
    c) 测试结果:
    在这里插入图片描述

  2. 测试2
    a) 测试数据用例:

    2 11 7 15 7
    7
    

    b) 测试数据用例2的特点:删除结点出现在表中,且是重复元素。
    c) 测试结果:
    在这里插入图片描述

  3. 测试3
    a) 测试数据用例:

    2 11 7 15 8
    8
    

    b) 测试数据用例3的特点:删除结点出现在表尾。
    c) 测试结果:
    在这里插入图片描述

5. 实验总结

在本次实验中,主要是熟悉创建双链表以及删除值的操作,以及要时刻判断删除指针时它本身以及它的后继是否为空,总体来说没有前面的题目难。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值