id:21 A. DS单链表--类实现
题目描述
用C++语言和类实现单链表,含头结点
属性包括:data数据域、next指针域
操作包括:插入、删除、查找
注意:单链表不是数组,所以位置从1开始对应首结点,头结点不放数据
类定义参考
cpp
#include <iostream>
using namespace std;
#define ok 0;
#define error -1;
//链表结点类定义
class ListNode
{
public:
int data;
ListNode* next;
ListNode() { next = NULL; }
};
//带头结点的单链表定义
class LinkList
{
public:
ListNode* head;
int len;
//操作定义
LinkList();
~LinkList();
ListNode* LL_index(int i); //返回第i个结点的指针,如果不存在,返回NULL
int LL_get(int i); //获取第i个元素的数据
int LL_insert(int i, int item); //把数值item插入第i个位置
int LL_del(int i); //删除第i个结点
void LL_display(); //输出单链表的内容
};
LinkList::LinkList()
{
head = new ListNode();
len = 0;
}
LinkList::~LinkList()
{
ListNode* p,* q;
p = head;
while (p != NULL)
{
q = p;
p = p->next;
delete q;
}
len = 0;
head = NULL;
}
void LinkList::LL_display()
{
ListNode* p;
p = head->next;
while (p)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
输入
第1行先输入n表示有n个数据,接着输入n个数据
第2行输入要插入的位置和新数据
第3行输入要插入的位置和新数据
第4行输入要删除的位置
第5行输入要删除的位置
第6行输入要查找的位置
第7行输入要查找的位置
输出
数据之间用空格隔开,
第1行输出创建后的单链表的数据
每成功执行一次操作(插入或删除),输出执行后的单链表数据
每成功执行一次查找,输出查找到的数据
如果执行操作失败(包括插入、删除、查找等失败),输出字符串error,不必输出单链表
输入样例
6 11 22 33 44 55 66
3 777
1 888
1
11
0
5
输出样例
11 22 33 44 55 66
11 22 777 33 44 55 66
888 11 22 777 33 44 55 66
11 22 777 33 44 55 66
error
error
44
题解
- #define ok 0; 和 #define error -1;:定义两个宏,分别表示操作成功和失败的返回值
ListNode
类表示链表的结点,包含两个成员变量,data
用于存储数据,next
是指向下一个节点的指针,构造函数将next
初始化为NULL
LinkList
类表示带头结点的单链表,包含两个成员变量,head
是指向头结点的指针,len
表示链表长度。构造函数LinkList()
初始化头结点,头节点是一个新的ListNode
对象。- 析构函数
~LinkList()
释放链表中的所有结点,ListNode* p, * q;
,声明两个指针,p
用于遍历列表,q
用于保存当前结点,以便在释放内存时使用。p = head;
将指针p
初始化为链表的头节点,我们需要从这个头结点开始释放链表中的所有结点。while (p != NULL)
,循环用于遍历链表中的所有结点,条件是p
不为空,即链表还没遍历完。q = p;
,将p
指针的当前值赋给q
。这样做是为了在释放内存后还可以访问到当前结点,因为p
将在下一行代码中被修改。p = p->next;
将p
指针移动到下一个结点。由于p
的值已经被保存到q
中,我们现在可以安全地删除当前的结点q
。delete q;
删除q
指向的结点。delete
运算符释放了q
指向的内存空间,避免了内存泄漏。 LL_index(int i)
返回第i
个结点的指针,如果不存在,返回NULL
。首先判断传入的参数是否在有效范围内。ListNode* p = head->next;
,将p
指针初始化为链表的第一个实际结点。由于head
是链表的头结点,实际的数据结点从head->next
开始。int j = 1;
,初始化计数器j
为 1,表示当前遍历到链表的第一个结点。while (p && j < i)
,循环遍历链表,直到找到第i
个结点或链表遍历完。p
,指向当前结点。如果p
为NULL
,则说明已经到达链表末尾。j < i
,表示当前结点的索引小于i
,继续遍历。p = p->next;
,将p
移动到下一个结点。j++
,将计数器j
增加 1,表示当前结点的索引增加。LL_get(int i)
获取第 i 个元素的数据。LL_insert(int i, int item)
在第 i 个位置插入数据 item。首先检查索引是否有效,然后将指针p
初始化为链表的头结点,定义一个计数器从0开始,遍历链表,知道插入位置的前一个结点,每次循环指向下一个结点,并增加计数器的值。检查p
是否为空或者j
是否超过了插入位置的前一个节点。p
为空表明链表的长度不足以达到位置i
,即位置i
不存在。然后,创建一个新节点s
,并将其数据域data
设置为item
。将新节点s
的next
指针指向原来位置i
的节点,即p->next
。更新前一个节点p
的next
指针,指向新节点s
,完成插入操作。LL_del(int i)
删除第 i 个结点。首先检查位置是否有效,然后创建一个指针指向链表的头结点,定义一个计数器j
从0开始。遍历链表,直到到达删除位置的前一个节点。然后检查p->next
是否为空或j
是否超出了删除位置的前一个节点。创建一个指针q
,指向要删除的节点(即p->next
)。将p
节点的next
指针更新为q
节点的next
,即跳过q
节点,直接指向q
节点之后的节点。这一步将q
节点从链表中移除。删除节点q
释放内存。delete q
将节点q
的内存归还给操作系统,防止内存泄漏。LL_display()
输出链表的内容。遍历链表,从头结点的下一个结点开始输出每个结点的数据。- 主函数中,首先创建一个链表,然后将输入进来的数据通过插入函数存储到链表中,直接输出,然后依次执行相应的操作
代码实现
cpp
#include <iostream>
using namespace std;
#define ok 0
#define error -1
//链表结点类定义
class ListNode
{
public:
int data;
ListNode* next;
ListNode() { next = NULL; }
};
//带头结点的单链表定义
class LinkList
{
public:
ListNode* head;
int len;
//操作定义
LinkList();
~LinkList();
ListNode* LL_index(int i); //返回第i个结点的指针,如果不存在,返回NULL
int LL_get(int i); //获取第i个元素的数据
int LL_insert(int i, int item); //把数值item插入第i个位置
int LL_del(int i); //删除第i个结点
void LL_display(); //输出单链表的内容
};
LinkList::LinkList()
{
head = new ListNode();
len = 0;
}
LinkList::~LinkList()
{
ListNode* p,* q;
p = head;
while (p != NULL)
{
q = p;
p = p->next;
delete q;
}
len = 0;
head = NULL;
}
ListNode* LinkList::LL_index(int i) //返回第i个结点的指针,如果不存在,返回NULL
{
if (i < 1 || i > len)
{
return NULL;
}
ListNode* p = head->next;
int j = 1;
while (p && j < i)
{
p = p->next;
j++;
}
return p;
}
int LinkList::LL_get(int i) //获取第i个元素的数据
{
ListNode* p = LL_index(i);
if (p)
{
return p->data;
}
else
{
return error;
}
}
int LinkList::LL_insert(int i, int item) //把数值item插入第i个位置
{
if (i < 1 || i > len + 1)
{
return error;
}
ListNode* p = head;
int j = 0;
while (p && (j < i - 1))
{
p = p->next;
j++;
}
if (!p || (j > i - 1))
{
return error;
}
ListNode* s = new ListNode();
s->data = item;
s->next = p->next;
p->next = s;
len++;
return ok;
}
int LinkList::LL_del(int i) //删除第i个结点
{
if (i < 1 || i > len)
{
return error;
}
ListNode* p = head;
int j = 0;
while ((p->next) && (j < i - 1))
{
p = p->next;
j++;
}
if (!(p->next) || (j > i - 1))
{
return error;
}
ListNode* q = p->next;
p->next = q->next;
delete q;
len--;
return ok;
}
void LinkList::LL_display()
{
ListNode* p;
p = head->next;
while (p)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
int main()
{
int n, i, d1, v1, data, ans;
cin >> n;
LinkList list; // 创建一个链表
for (i = 0; i < n; i++)
{
cin >> data;
list.LL_insert(i + 1, data);
}
list.LL_display();
//插入
cin >> d1 >> v1;
ans = list.LL_insert(d1, v1);
if (ans >= 0)
{
list.LL_display();
}
else
{
cout << "error" << endl;
}
cin >> d1 >> v1;
ans = list.LL_insert(d1, v1);
if (ans >= 0)
{
list.LL_display();
}
else
{
cout << "error" << endl;
}
//删除
cin >> d1;
ans = list.LL_del(d1);
if (ans >= 0)
{
list.LL_display();
}
else
{
cout << "error" << endl;
}
cin >> d1;
ans = list.LL_del(d1);
if (ans >= 0)
{
list.LL_display();
}
else
{
cout << "error" << endl;
}
//查找
cin >> d1;
ans = list.LL_get(d1);
if (ans >= 0)
{
cout << ans << endl;
}
else
{
cout << "error" << endl;
}
cin >> d1;
ans = list.LL_get(d1);
if (ans >= 0)
{
cout << ans << endl;
}
else
{
cout << "error" << endl;
}
return 0;
}
id:22 B. DS单链表--结点交换
题目描述
用C++实现含头结点的单链表,然后实现单链表的两个结点交换位置。
注意不能简单交换两个结点包含数据,必须通过修改指针来实现两个结点的位置交换
交换函数定义可以参考:
cpp
swap(int pa, int pb) //pa和pb表示两个结点在单链表的位置序号
swap (ListNode * p, ListNode * q) //p和q表示指向两个结点的指针
输入
第1行先输入n表示有n个数据,接着输入n个数据
第2行输入要交换的两个结点位置
第3行输入要交换的两个结点位置
输出
第一行输出单链表创建后的所有数据,数据之间用空格隔开
第二行输出执行第1次交换操作后的单链表数据,数据之间用空格隔开
第三行输出执行第2次交换操作后的单链表数据,数据之间用空格隔开
如果发现输入位置不合法,输出字符串error,不必输出单链表
输入样例
5 11 22 33 44 55
1 4
2 6
输出样例
11 22 33 44 55
44 22 33 11 55
error
提示
注意要用链表实现哦!
题解
- 还是定义两个类,一个是链表结点类定义,一个是带头结点的单链表定义,结点类定义和第一题相同,单链表定义只有构造析构,插入,两个交换函数和输出函数
int swap(int pa, int pb); //pa和pb表示两个结点在单链表的位置序号
,这个函数的目的是通过节点的序号找到这个节点和他自己的前驱节点,使之作为void swap(ListNode* prevP, ListNode* prevQ, ListNode* p, ListNode* q); //p和q表示指向两个结点的指针
函数的参数,在此函数中,首先判断两个位置是否有效,然后定义两个指针,一个指针指向头结点,另一个指针指向头结点的下一个节点,然后通过循环遍历列表直到前驱节点指向指定节点的前一个结点,另一个指针直接指向此结点,两个节点两个循环,然后调用swap(prevP, prevQ, p, q)
函数- 在
swap(prevP, prevQ, p, q)
函数中,首先判断两个节点的指针是否指向同一个位置,然后将两个前驱节点的下一个结点指向需要交换位置的结点,此时链表的前一个指向改了,然后将链表的后一个指向通过一个临时变量互换
代码实现
cpp
#include <iostream>
using namespace std;
#define ok 0
#define error -1
//链表结点类定义
class ListNode
{
public:
int data;
ListNode* next;
ListNode() { next = NULL; }
};
//带头结点的单链表定义
class LinkList
{
public:
ListNode* head;
int len;
//操作定义
LinkList();
~LinkList();
int LL_insert(int i, int item); //把数值item插入第i个位置
int swap(int pa, int pb); //pa和pb表示两个结点在单链表的位置序号
void swap(ListNode* prevP, ListNode* prevQ, ListNode* p, ListNode* q); //p和q表示指向两个结点的指针
void LL_display(); //输出单链表的内容
};
LinkList::LinkList()
{
head = new ListNode();
len = 0;
}
LinkList::~LinkList()
{
ListNode* p, * q;
p = head;
while (p != NULL)
{
q = p;
p = p->next;
delete q;
}
len = 0;
head = NULL;
}
int LinkList::LL_insert(int i, int item) //把数值item插入第i个位置
{
if (i < 1 || i > len + 1)
{
return error;
}
ListNode* p = head;
int j = 0;
while (p && (j < i - 1))
{
p = p->next;
j++;
}
if (!p || (j > i - 1))
{
return error;
}
ListNode* s = new ListNode();
s->data = item;
s->next = p->next;
p->next = s;
len++;
return ok;
}
int LinkList::swap(int pa, int pb) //pa和pb表示两个结点在单链表的位置序号
{
if (pa < 1 || pa > len || pb < 1 || pb > len || pa == pb)
{
return error;
}
ListNode* prevP = head;
ListNode* p = head->next;
for (int i = 1; i < pa; i++)
{
prevP = p;
p = p->next;
}
ListNode* prevQ = head;
ListNode* q = head->next;
for (int i = 1; i < pb; i++)
{
prevQ = q;
q = q->next;
}
swap(prevP, prevQ, p, q);
return ok;
}
void LinkList::swap(ListNode* prevP, ListNode* prevQ, ListNode* p, ListNode* q) //p和q表示指向两个结点的指针
{
if (p == q) return;
if (prevP) prevP->next = q;
if (prevQ) prevQ->next = p;
ListNode* temp = p->next;
p->next = q->next;
q->next = temp;
}
void LinkList::LL_display()
{
ListNode* p;
p = head->next;
while (p)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
int main()
{
int n, i, data, d1, d2, ans;
cin >> n;
LinkList list; // 创建一个链表
for (i = 0; i < n; i++)
{
cin >> data;
list.LL_insert(i + 1, data);
}
list.LL_display();
cin >> d1 >> d2;
ans = list.swap(d1, d2);
if (ans == 0)
{
list.LL_display();
}
else
{
cout << "error" << endl;
}
cin >> d1 >> d2;
ans = list.swap(d1, d2);
if (ans == 0)
{
list.LL_display();
}
else
{
cout << "error" << endl;
}
return 0;
}
id:23 C. DS单链表--合并
题目描述
假定两个单链表是递增有序,定义并实现以下函数,完成两个单链表的合并,继续保持递增有序
cpp
int LL_merge(ListNode *La, ListNode *Lb)
输入
第1行先输入n表示有n个数据,接着输入n个数据
第2行先输入m表示有M个数据,接着输入m个数据
输出
输出合并后的单链表数据,数据之间用空格隔开
输入样例1
3 11 33 55
4 22 44 66 88
输出样例1
11 22 33 44 55 66 88
输入样例2
3 11 33 55
5 22 33 44 66 88
输出样例2
11 22 33 44 55 66 88
题解
- 题目要求合并并且实现有效递增,还要去除重复元素,首先还是定义两个类,一个节点类,一个带头结点的单链表类
- 在单链表类的合并函数中,传入的参数是两个单链表的指向头结点的指针,我的思路是把b链表合并进a链表。具体内容是,定义一个计数器,一个指针指向一个单链表的头结点的下一个位置,另一个也是。用一个循环,当两个指针都不为空的时候,判断两个指针所指向的位置存储的数字大小,还有是否相等,如果
pa->data < pb->data
,因为是合并进a链表,所以如果a小,则其数字在链表中的位置不用改变,所以指针更新到指向下一个位置,然后计数器加一,如果pa->data > pb->data
,则表示要将b链表的元素插进a链表中,所以我们调用插入函数,然后更新b的指针指向下一个位置,计数器加一,如果两个相等,则表示a中的这个元素要留在a链表中,所以将b的指针指向下一位,让b的下一位与a的这一位进行比较。循环结束后,判断a链表是否为空,如果不为空,则说明循环结束是因为b链表为空,又因为我们是合并到a链表中,b链表又没有元素可以合并了,所以我们可以直接返回,如果a链表为空,则说明b链表中还有元素要穿插进来,所以我们将b链表不为空,即使指向b链表元素的指针不为空作为循环条件,在循环中,将b链表中的值一个个插入进a链表中,用函数
代码实现
cpp
#include <iostream>
using namespace std;
#define ok 0
#define error -1
//链表结点类定义
class ListNode
{
public:
int data;
ListNode* next;
ListNode() { next = NULL; }
};
//带头结点的单链表定义
class LinkList
{
public:
ListNode* head;
int len;
//操作定义
LinkList();
~LinkList();
int LL_insert(int i, int item); //把数值item插入第i个位置
void LL_display(); //输出单链表的内容
int LL_merge(ListNode* La, ListNode* Lb);
};
LinkList::LinkList()
{
head = new ListNode();
len = 0;
}
LinkList::~LinkList()
{
ListNode* p, * q;
p = head;
while (p != NULL)
{
q = p;
p = p->next;
delete q;
}
len = 0;
head = NULL;
}
int LinkList::LL_insert(int i, int item) //把数值item插入第i个位置
{
if (i < 1 || i > len + 1)
{
return error;
}
ListNode* p = head;
int j = 0;
while (p && (j < i - 1))
{
p = p->next;
j++;
}
if (!p || (j > i - 1))
{
return error;
}
ListNode* s = new ListNode();
s->data = item;
s->next = p->next;
p->next = s;
len++;
return ok;
}
void LinkList::LL_display()
{
ListNode* p;
p = head->next;
while (p)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
int LinkList::LL_merge(ListNode* La, ListNode* Lb)
{
int j = 1;
ListNode* pa = La->next;
ListNode* pb = Lb->next;
while (pa && pb)
{
if (pa->data < pb->data)
{
pa = pa->next;
j++;
}
else if (pa->data > pb->data)
{
LL_insert(j, pb->data);
pb = pb->next;
j++;
}
else
{
pb = pb->next;
}
}
if (pa == NULL)
{
while (pb)
{
LL_insert(j, pb->data);
pb = pb->next;
j++;
}
}
return ok;
}
int main()
{
int n, m, i, data;
cin >> n;
LinkList list1;
for (i = 0; i < n; i++)
{
cin >> data;
list1.LL_insert(i + 1, data);
}
cin >> m;
LinkList list2;
for (i = 0; i < m; i++)
{
cin >> data;
list2.LL_insert(i + 1, data);
}
list1.LL_merge(list1.head, list2.head);
list1.LL_display();
return 0;
}
id:25 D. DS链表---学生宿舍管理
题目描述
假设某校有20间宿舍,宿舍编号101,102,...,120。每间只住一名学生。初始部分宿舍已用。用两个链表(已用宿舍链表和可用宿舍链表)维护宿舍的管理,实现宿舍分配、宿舍交回。
约定已用宿舍链表按宿舍号升序链接。初始可用宿舍链表也按宿舍号升序链接。
宿舍分配从可用宿舍链表中摘取第一间宿舍分配给学生。学生交回的宿舍挂在可用宿舍链表最后。
备注:使用list容器或静态链表。不用考虑宿舍分配和交回不成功的情况。
输入
初始宿舍状态,第一行输入n,表示已用宿舍n间
后跟n行数据,每行格式为:学生姓名 宿舍号
操作次数m,后跟m行操作,操作格式如下:
assign 学生 //为学生分配宿舍,从可用宿舍链表头摘取一间宿舍,
//按宿舍号升序挂在已用宿舍链表中。
return 宿舍号 //学生退宿舍,删除已用宿舍链表中对应结点,
//挂在可用宿舍链表尾部。
display_free //输出可用宿舍链表信息。
display_used //输出已用宿舍链表信息。
输出
display_free依次输出当前可用宿舍链表中的宿舍号,具体格式见样例。
display_used依次输出当前已用宿舍链表中的学生和宿舍号,具体格式见样例。
输入样例
5
李明 103
张三 106
王五 107
钱伟 112
章立 118
8
assign 李四
assign 赵六
return 118
return 101
assign 马山
display_used
assign 林立
display_free
输出样例
赵六(102)-李明(103)-马山(104)-张三(106)-王五(107)-钱伟(112)
108-109-110-111-113-114-115-116-117-119-120-118-101
提示
list是一种序列式容器, list实际上就构成了一个双向循环链,
List类使用的参考代码
-
包含头文件 : #include
-
List定义和初始化:
listlst1; //创建空list
list lst2(5); //创建含有5个元素的list
listlst3(3,2); //创建含有3个元素的list
listlst4(lst2); //使用lst2初始化lst4
listlst5(lst2.begin(),lst2.end()); //同lst4
-
创建一个list对象l(注意list是模板类):list l; //堆栈的数据类型是字符型
-
把一个字符ct添加到链表末尾: s.push_back(ct);
-
把一个字符ct插入到链表头部: s.push_front(ct);
-
获取链表第一个元素和最后一个元素:front()和back(),获取链表第一个元素,放入变量c2: c2 = s.front();
-
删除链表第一个元素和最后一个元素
- pop_front()和pop_back();
-
判断 判断list是否为空:empty(): l.empty(),如果为空则函数返回true,如果不空则返回false
-
begin() 返回指向第一个元素的迭代器
-
end() 返回末尾的迭代器
-
rbegin() 返回指向第一个元素的逆向迭代器
-
rend() 指向list末尾的逆向迭代器
程序示列:
cpp
#include <iostream>
using namespace std;
typedef list<int> LISTINT;
void main()
{
//用LISTINT创建一个list对象
LISTINT listOne;
//声明i为迭代器
LISTINT::iterator i;
listOne.push_front(3);
listOne.push_front(2);
listOne.push_front(1);
listOne.push_back(4);
listOne.push_back(5);
listOne.push_back(6);
cout << "listOne.begin()--- listOne.end():" << endl;
for (i = listOne.begin(); i != listOne.end(); ++i)
cout << *i << " ";
cout << endl; //正向输出
LISTINT::reverse_iterator ir;
cout << "listOne.rbegin()---listOne.rend():" << endl;
for (ir = listOne.rbegin(); ir != listOne.rend(); ir++) {
cout << *ir << " ";
}
cout << endl; //反向输出
}
题解
- 首先创建一个宿舍类,类里面有成员函数,住这个宿舍的人的名字和宿舍号码,还有一个构造函数
- 定义一个比较函数,接受两个类的类型参数,函数的功能是比较这两个对象的num属性,
- 在主函数中,定义两个链表,一个是
Cdorm
属性的已用宿舍链表,一个是整数属性的可用宿舍链表,已用宿舍链表中存储姓名和宿舍号,可用宿舍链表只存储宿舍号,用一个for
循环将数据输入,然后用构造函数初始化,再用push_back()
将数据存储在链表,再用一个循环将可用宿舍号初始化
代码实现
cpp
#include<iostream>
#include <list>
using namespace std;
class Cdorm
{
public:
string name;
int num;
Cdorm(string n1, int n2);
};
Cdorm::Cdorm(string n1, int n2)
{
name = n1;
num = n2;
}
// 比较函数,用于按宿舍号升序排序
bool cmp(const Cdorm& a, const Cdorm& b)
{
return a.num < b.num;
}
int main()
{
int n, m, i, num;
string opera, name;
list<Cdorm> used_dorm; //已用宿舍链表
list<int> free_dorm; //可用宿舍链表
cin >> n;
for (i = 0; i < n; i++)
{
cin >> name >> num;
Cdorm d(name, num);
used_dorm.push_back(d);
}
//将可用宿舍号初始化为101到120
for (i = 101; i <= 120; i++)
{
free_dorm.push_back(i);
}
//从已用宿舍链表中移除宿舍号
for (const auto& d : used_dorm)
{
free_dorm.remove(d.num);
}
//操作
cin >> m;
for (i = 0; i < m; i++)
{
cin >> opera;
//分配宿舍
if (opera == "assign")
{
cin >> name;
//没有空宿舍
if (free_dorm.empty())
{
continue;
}
//从可用宿舍链表中获取第一个宿舍
int dorm_num = free_dorm.front();
//删除链表第一个元素
free_dorm.pop_front();
// 将其添加到已用宿舍链表中
Cdorm d(name, dorm_num);
//把字符添加到链表末尾
used_dorm.push_back(d);
used_dorm.sort(cmp);
}
//退回宿舍
else if (opera == "return")
{
cin >> num;
//从已用宿舍链表中找到并删除指定宿舍
for (auto it = used_dorm.begin(); it != used_dorm.end(); ++it)
{
if (it->num == num)
{
free_dorm.push_back(num);
used_dorm.erase(it);
break;
}
}
}
//输出可用宿舍链表信息
else if (opera == "display_free")
{
int first = 0; //第一个
for (const int& dorm : free_dorm)
{
if (first == 0)
{
cout << dorm;
first = 1;
}
else
{
cout << "-" << dorm;
}
}
cout << endl;
}
//输出已用宿舍链表信息
else if (opera == "display_used")
{
int first = 0; //第一个
for (const Cdorm& d : used_dorm)
{
if (first == 0)
{
cout << d.name << "(" << d.num << ")";
first = 1;
}
else
{
cout << "-" << d.name << "(" << d.num << ")";
}
}
cout << endl;
}
}
return 0;
}
id:31 E. DS单链表---删除重复元素
题目描述
给定n个整数,按输入顺序建立单链表,删除其中的重复数字,输出结果链表。(要求不可以构建新结点,不可以定义新链表。在原链表上删除。)
输入
测试次数t
每组测试数据一行:
n(表示有n个整数),后跟n个数字
输出
对每组测试数据,输出删除重复数字后的结果链表表长和每个元素,具体格式见样例。
输入样例
3
10 1 2 3 4 1 2 10 20 30 20
5 1 1 1 1 1
6 20 22 22 22 22 20
输出样例
7: 1 2 3 4 10 20 30
1: 1
2: 20 22
题解
- 重点是用两个循环将有重复的数字删除
代码实现
cpp
#include <iostream>
using namespace std;
#define ok 0
#define error -1
//链表结点类定义
class ListNode
{
public:
int data;
ListNode* next;
ListNode() { next = NULL; }
};
//带头结点的单链表定义
class LinkList
{
public:
ListNode* head;
int len;
//操作定义
LinkList();
~LinkList();
int LL_insert(int i, int item); //把数值item插入第i个位置
void LL_del(); //删除
void LL_display(); //输出单链表的内容
};
LinkList::LinkList()
{
head = new ListNode();
len = 0;
}
LinkList::~LinkList()
{
ListNode* p, * q;
p = head;
while (p != NULL)
{
q = p;
p = p->next;
delete q;
}
len = 0;
head = NULL;
}
int LinkList::LL_insert(int i, int item) //把数值item插入第i个位置
{
if (i < 1 || i > len + 1)
{
return error;
}
ListNode* p = head;
int j = 0;
while (p && (j < i - 1))
{
p = p->next;
j++;
}
if (!p || (j > i - 1))
{
return error;
}
ListNode* s = new ListNode();
s->data = item;
s->next = p->next;
p->next = s;
len++;
return ok;
}
void LinkList::LL_del() //删除
{
ListNode* p = head->next; // 从第一个有效节点开始
while (p != NULL)
{
ListNode* q = p;
while (q->next != NULL)
{
if (q->next->data == p->data)
{
// 删除重复的节点
ListNode* temp = q->next;
q->next = q->next->next;
delete temp;
len--;
}
else
{
q = q->next;
}
}
p = p->next;
}
}
void LinkList::LL_display()
{
ListNode* p;
p = head->next;
cout << len << ":";
while (p)
{
cout << " " << p->data;
p = p->next;
}
cout << endl;
}
int main()
{
int t, n, i, j, data;
cin >> t;
for (i = 0; i < t; i++)
{
LinkList list; // 创建一个链表
cin >> n;
for (j = 0; j < n; j++)
{
cin >> data;
list.LL_insert(j + 1, data);
}
list.LL_del();
list.LL_display();
}
return 0;
}