目录
1. 实验内容及上机实验所用平台
1.1 实验内容
某非空单链表 L 中所有元素为整数,设计一个算法将所有小于零的节点移到所有大于等于零的节点的前面。注意测试负值结点是表头、表尾元素结点的不同情况。
1.2 设计思路
由例子来设计算法。指针 last 永远指向开头的最后一个负值,通过指针 p、q、last 来移动结点,将负值从链表中提取出来,再将负值插入到正值前面。



1.3 实验平台软件
Dev-C++.
2. 数据结构
非空单链表,有指向后继结点的 next 指针,尾结点的 next 域置为 NULL。
3. 设计描述与分析
3.1 伪代码
输入:字符串 str。
输出:移动后新的单链表。
// 将字符串str转化为数组num
// 利用数组num创建循环单链表
// 生成结点*last ← head, *p ← head→next, *q ← (p → next)
// 跳过以负整数开头的结点
while p!= NULL
if p指向的值 ≤ 0
// 将此结点移动到正值结点前面
// 指针进行适当移动(见设计思路步骤)
end if
else
q ← (q → next)
p ← (q → next)
end else
end while
3.2 流程图

3.3 主要代码段
void Move() {
LinkNode *last = head;
LinkNode *p = head -> next;
while (p != NULL && p -> val < 0) { // 跳过以负整数开头的结点
last = last -> next;
p = p -> next;
}
LinkNode *q = last;
while (p != NULL) {
if (p -> val < 0) { // 找到负整数结点 p
q -> next = p -> next; // 删除 p 结点
p -> next = last -> next; // 将结点 p 插入到 last 结点后
last -> next = p; // 连接单链表
last = p; // 结点 last 后移 1 个结点
p = q -> next; // 结点 p 指向 last 结点的后继结点
}
else { // 结点 p 不是 负整数结点,所以结点 last、p 后移一个结点
q = q -> next;
p = q -> next;
}
}
}
3.4 源代码
需要先在源代码目录下新建 in.txt 文件,在此文件下输入要测试的数据。
#include <iostream>
#include <string>
using namespace std;
struct LinkNode { // 不带头结点的单链表结点类型
int val;
LinkNode *next;
LinkNode():next(NULL) {} // 构造函数
LinkNode(int x): val(x), next(NULL) {} // 重载构造函数
};
class LinkList {
public:
LinkNode *head; // 单链表的头结点
LinkList() // 构造函数,创建一个空单链表
{
head = new LinkNode();
}
void CreateList(int a[], int n) { // 建立循环单链表
LinkNode *s, *r = head; // r为尾结点指针,开始时指向头结点
for (int i = 0; i < n; i++) {
s = new LinkNode(a[i]); // 创建数据结点s
r -> next = s; // 将 s 结点链接到末尾
r = s;
}
r -> next = NULL; // 将尾结点的 next 域置为 NULL
}
void Move() {
LinkNode *last = head;
LinkNode *p = head -> next;
while (p != NULL && p -> val < 0) { // 跳过以负整数开头的结点
last = last -> next;
p = p -> next;
}
LinkNode *q = last;
while (p != NULL) {
if (p -> val < 0) { // 找到负整数结点 p
q -> next = p -> next; // 删除 p 结点
p -> next = last -> next; // 将结点 p 插入到 last 结点后
last -> next = p; // 连接单链表
last = p; // 结点 last 后移 1 个结点
p = q -> next; // 结点 p 指向 last 结点的后继结点
}
else { // 结点 p 不是 负整数结点,所以结点 last、p 后移一个结点
q = q -> next;
p = q -> next;
}
}
}
void DispList() // 输出单链表所有结点值
{
LinkNode *p;
p = head -> next; // p指向开始结点
while (p != NULL) // p不为 NULL,输出 p 结点的 val
{
cout << p -> val << " ";
p = p -> next; // p移向下一个结点
}
cout << endl;
}
};
int main() {
cout << "\t\t第4题 - 负值节点前移\n\n";
cout << "---------------------------------------------------\n\n";
freopen("in.txt", "r", stdin);
string str;
while (cin >> str); // 读取文件数据(当字符串读取)
cout << "样例输入:" << str << endl;
string str_temp = "";
int num_temp[1001] = {0}, num[1001] = {0}, cnt_temp = 0, cnt = 0, x = 0;
bool flag = false; // 正数
for(int i = 0; i < str.length(); i++) num_temp[cnt_temp++] = str[i] - '0'; // 将字符全部转为数字
// 提取字符串中的数字
for (int i = 0; i < cnt_temp; i++) {
if (num_temp[i] >= 0 && num_temp[i] <= 9) x = x * 10 + num_temp[i];
else if (num_temp[i] == -3) flag = true;
else {
if (flag) {
x = -x;
flag = false;
}
num[cnt++] = x;
x = 0;
i++;
}
if (i == cnt_temp - 1) {
if (flag) {
x = -x;
flag = false;
}
num[cnt++] = x;
}
}
LinkList L;
L.CreateList(num, cnt); // 创建循环单链表
cout << "\n\n样例输出:";
L.Move();
L.DispList();
cout << "\n\n";
freopen("CON", "r", stdin); // 为了可直接查看exe可执行文件,需要将权限返回键盘
system("pause");
return 0;
}
4. 调试过程
-
测试1
a) 测试数据用例:9,8,-6,7,4,-3,-6
b) 测试数据用例1的特点:该数据用例中负值结点出现在表中和表尾。
c) 测试结果:

-
测试2
a) 测试数据用例:-3,9,8,-5,7,4
b) 测试数据用例2的特点:该数据用例中负值结点出现在表首和表中。
c) 测试结果:

5. 实验总结
在本次实验中,最重要的是如何通过 3 个指针的移动来实现题目的要求。而最好的方法就是拿一个比较全面的例子来模拟它的移动情况,通过模拟的情况来判定指针要如何移动。同样本题还是输入的一个字符串,至于如何能够有效的分割出来我们要的数字,还需要之后继续研究。
本文介绍了如何使用Dev-C++设计并实现一个算法,将给定单链表中所有小于零的节点移动到所有大于等于零的节点前面,通过伪代码、流程图和代码段详细展示了设计过程和调试测试案例。
731

被折叠的 条评论
为什么被折叠?



