DS单链表 基础例题
A.单链表的类实现
用C++语言和类实现单链表,含头结点
属性包括:data数据域、next指针域
操作包括:插入、删除、查找
注意:单链表不是数组,所以位置从1开始对应首结点,头结点不放数据
输入
第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
题解
#include<bits/stdc++.h>
using namespace std;
#define ok 1
#define error 0
class ListNode {
public:
int data; //数据
ListNode *next; //next指针
ListNode() {
next = NULL;
}
};
class LinkList {
public:
ListNode *head;
int len;
LinkList();
~LinkList();
ListNode *LL_index(int i); //返回目标位置指针
int LL_get(int i); //获取数据
int LL_insert(int i, int item); //插入数据
int LL_del(int i); //删除数据
void LL_display(); //输出数据
};
void LinkList::LL_display(){
for(ListNode* i = head->next; i != NULL; i = i->next){
cout << i->data << " ";
}cout << endl;
}
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) {
int j=0;
ListNode *p;
p=head;
while(p && j<i-1) {
p=p->next;
++j;
}
if(!p || j>i-1) {
return NULL;
} else return p;
}
int LinkList::LL_insert(int i,int item) {
ListNode *p;
if(LL_index(i) == NULL)
return error;
else
p=LL_index(i);
ListNode *s;
s=new ListNode();
s->data=item;
s->next=p->next;
p->next=s;
len++;
return ok;
}
int LinkList::LL_del(int i) {
ListNode *p;
if(LL_index(i) == NULL)
return error;
else {
p=LL_index(i);
ListNode *q;
q=p->next;
p->next=q->next;
delete q;
len--;
return ok;
}
}
int LinkList::LL_get(int i) {
if(i<=0|| i>len)
return error;
else {
ListNode *p;
p=head;
int j=0;
while(p->next&& j<=i-1) {
p=p->next;
++j;
}
int num=p->data;
return num;
}
}
int main() {
LinkList li;
int n,item,i;
cin >> n;
//输入
for(i = 1; i <= n; i++){
cin >> item;
li.LL_insert(i,item);
}
li.LL_display();
//插入
cin >> i >> item;
if(li.LL_insert(i,item)) li.LL_display();
else cout << "error" << endl;
cin >> i >> item;
if(li.LL_insert(i,item)) li.LL_display();
else cout << "error" << endl;
//删除
cin >> i;
if(li.LL_del(i)) li.LL_display();
else cout << "error" << endl;
cin >> i;
if(li.LL_del(i)) li.LL_display();
else cout << "error" << endl;
//查找
cin >> i;
if(item = li.LL_get(i)) cout << item << endl;
else cout << "error" << endl;
cin >> i;
if(item = li.LL_get(i)) cout << item << endl;
else cout << "error" << endl;
return 0;
}
B. DS单链表–结点交换
用C++实现含头结点的单链表,然后实现单链表的两个结点交换位置。
注意不能简单交换两个结点包含数据,必须通过修改指针来实现两个结点的位置交换
交换函数定义可以参考:
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
题解
将两个节点的前驱和后继交换即可
#include<bits/stdc++.h>
using namespace std;
#define ok 1
#define error 0
class ListNode {
public:
int data;
ListNode *next;
ListNode() {
next = NULL;
}
};
class LinkList {
public:
ListNode *head;
int len;
LinkList();
~LinkList();
ListNode *LL_index(int i);
int LL_get(int i);
int LL_insert(int i, int item);
int LL_del(int i);
void LL_display();
int LL_swap(int pa,int pb);
};
// 题目要求函数
int LinkList::LL_swap(int pa,int pb)
{
//非法访问跳过
if(pa < 1 || pb < 1 || pa > len || pb > len)
return error;
//获取节点指针
ListNode *a = LL_index(pa);
ListNode *b = LL_index(pb);
//交换后继
ListNode *tmp = a -> next -> next;
a -> next -> next = b -> next -> next;
b -> next -> next = tmp;
//交换前驱
tmp = a -> next;
a -> next = b -> next;
b -> next = tmp;
return ok;
}
void LinkList::LL_display(){
for(ListNode* i = head->next; i != NULL; i = i->next){
cout << i->data << " ";
}cout << endl;
}
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) {
int j=0;
ListNode *p;
p=head;
while(p && j<i-1) {
p=p->next;
++j;
}
if(!p || j>i-1) {
return NULL;
} else return p;
}
int LinkList::LL_insert(int i,int item) {
ListNode *p;
if(LL_index(i) == NULL)
return error;
else
p=LL_index(i);
ListNode *s;
s=new ListNode();
s->data=item;
s->next=p->next;
p->next=s;
len++;
return ok;
}
int LinkList::LL_del(int i) {
ListNode *p;
if(LL_index(i) == NULL)
return error;
else {
p=LL_index(i);
ListNode *q;
q=p->next;
p->next=q->next;
delete q;
len--;
return ok;
}
}
int LinkList::LL_get(int i) {
if(i<=0|| i>len)
return error;
else {
ListNode *p;
p=head;
int j=0;
while(p->next&& j<=i-1) {
p=p->next;
++j;
}
int num=p->data;
return num;
}
}
int main() {
LinkList li;
int n,item,i;
cin >> n;
//输入
for(i = 1; i <= n; i++){
cin >> item;
li.LL_insert(i,item);
}
li.LL_display();
//交换
int pa,pb;
cin >> pa >> pb;
if(li.LL_swap(pa,pb)) li.LL_display();
else cout << "error" << endl;
cin >> pa >> pb;
if(li.LL_swap(pa,pb)) li.LL_display();
else cout << "error" << endl;
return 0;
}
C. DS单链表–合并
假定两个单链表是递增有序,定义并实现以下函数,完成两个单链表的合并,继续保持递增有序
int LL_merge(ListNode *La, ListNode *Lb)
输入
第1行先输入n表示有n个数据,接着输入n个数据
第2行先输入m表示有M个数据,接着输入m个数据
输出
输出合并后的单链表数据,数据之间用空格隔开
样例输入
3 11 33 55
4 22 44 66 88
样例输出
11 22 33 44 55 66 88
题解
这里给出两个方法,完整代码中给出的是方法一
方法一:直接链接节点
这里是合并得到新的头节点,但是原来的节点没有改变。就是说如果原链表变化,该新链表中的节点数据也会发生变化。
ListNode* LL_merge(ListNode* list1, ListNode* list2) {
//创建新节点
ListNode* preHead = new ListNode();
ListNode *head = preHead;
//链接节点
while(list1 != NULL|| list2 != NULL)
{
if(list1 == NULL)
{
head->next = list2;
list2 = list2->next;
}
else if(list2 == NULL)
{
head->next =list1;
list1 = list1->next;
}
else if(list1->data > list2->data)
{
head->next = list2;
list2 = list2->next;
}
else
{
head->next =list1;
list1 = list1->next;
}
head = head->next;
}
//返回新的头节点
return preHead->next->next;
}
方法二:通过原链表数据,创建新节点再插入。
这里是使用的 La
链表为合并链表,也可以创建一个新的链表 Lc
int LL_merge(ListNode *La, ListNode *Lb){
//LinkList Lc;
//ListNode *p = Lc.head;
ListNode *p;
p = La;
for(ListNode *i = La->next, *j = Lb->next; i != NULL || j != NULL;)
{
if(i == NULL || (j != NULL && j->data < i->data)){
ListNode *s = new ListNode;
s->data = j -> data;
p -> next = s;
j = j -> next;
}
else if(j == NULL || (i != NULL && j->data >= i->data)){
ListNode *s = new ListNode;
s->data = i -> data;
p -> next = s;
i = i -> next;
}
if(p->next != NULL) p = p -> next;
}
//Lc.LL_display();
return 1;
}
完整代码
#include<bits/stdc++.h>
using namespace std;
#define ok 1
#define error 0
class ListNode {
public:
int data;
ListNode *next;
ListNode() {
next = NULL;
}
};
class LinkList {
public:
ListNode *head;
int len;
LinkList();
~LinkList();
ListNode *LL_index(int i);
int LL_get(int i);
int LL_insert(int i, int item);
int LL_del(int i);
void LL_display();
};
void LinkList::LL_display(){
for(ListNode* i = head->next; i != NULL; i = i->next){
cout << i->data << " ";
}cout << endl;
}
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) {
int j=0;
ListNode *p;
p=head;
while(p && j<i-1) {
p=p->next;
++j;
}
if(!p || j>i-1) {
return NULL;
} else return p;
}
int LinkList::LL_insert(int i,int item) {
ListNode *p;
if(LL_index(i) == NULL)
return error;
else
p=LL_index(i);
ListNode *s;
s=new ListNode();
s->data=item;
s->next=p->next;
p->next=s;
len++;
return ok;
}
int LinkList::LL_del(int i) {
ListNode *p;
if(LL_index(i) == NULL)
return error;
else {
p=LL_index(i);
ListNode *q;
q=p->next;
p->next=q->next;
delete q;
len--;
return ok;
}
}
int LinkList::LL_get(int i) {
if(i<=0|| i>len)
return error;
else {
ListNode *p;
p=head;
int j=0;
while(p->next&& j<=i-1) {
p=p->next;
++j;
}
int num=p->data;
return num;
}
}
// 合并函数
ListNode* LL_merge(ListNode* list1, ListNode* list2) {
ListNode* preHead = new ListNode();
ListNode *head = preHead;
while(list1 != NULL|| list2 != NULL)
{
if(list1 == NULL)
{
head->next = list2;
list2 = list2->next;
}
else if(list2 == NULL)
{
head->next =list1;
list1 = list1->next;
}
else if(list1->data > list2->data)
{
head->next = list2;
list2 = list2->next;
}
else
{
head->next =list1;
list1 = list1->next;
}
head = head->next;
}
return preHead->next->next;
}
int main() {
LinkList la,lb;
int n,item,i;
cin >> n;
//输入
for(i = 1; i <= n; i++){
cin >> item;
la.LL_insert(i,item);
}
cin >> n;
for(i = 1; i <= n; i++){
cin >> item;
lb.LL_insert(i,item);
}
//
la.head = LL_merge(la.head,lb.head);
la.LL_display();
return 0;
}
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
题解
通过结构 Student
来存储 name
和 id
即姓名和房间号两个数据,方便后续插入比较。
这里采用直接比较,直接插入对应排序位置。
不过 list
中有自定义的 sort
的函数可以使用,可以自定义一个 sort
来在每次输出前进行一次排序
#include<bits/stdc++.h>
using namespace std;
//学生房间结构体定义
struct student{
string name;
int id;
student(string na,int i){
name = na; id = i;
}
};
int main() {
//初始化链表
list <student> stu;
list <int> fre;
//初始化迭代器
list<int>::iterator i;
list<student>::iterator j;
//哈希表备用
map<int,int> ha;
//初始化
int n,it;
cin >> n;
string name;
for(int i = 0; i < n; i++) {
cin >> name >> it;
stu.push_back(student(name,it));
ha[it]++;
}
for(int i = 101; i <= 120; i++) {
if(!ha[i]) {
fre.push_back(i);
}
}
//房间分配收回操作
int m;
string sign;
cin >> m;
while(m--) {
cin >> sign;
//拿取房间
if(sign == "assign") {
cin >> name;
int tmp = fre.front();
for(j = stu.begin(); j != stu.end(); ){
//找到第一个比拿取房间id大的房间或到达末尾,插入房间数据
if(j->id > tmp || ++j == stu.end()){
stu.insert(j,1,student(name,tmp));
break;
}
}
fre.pop_front();
}
//返回房间
if(sign == "return") {
cin >> it;
for(j = stu.begin(); j != stu.end();j++) {
if(j->id == it) {
stu.erase(j);
fre.push_back(it);
break;
}
}
}
//输出已使用房间
if(sign == "display_used") {
for(j = stu.begin(); j != stu.end();) {
cout << j->name << "(" << j->id << ")" ;
if(++j != stu.end()) cout << "-";
}
cout << endl;
}
//输出未使用房间
if(sign == "display_free") {
for(i = fre.begin(); i != fre.end();) {
cout << *i ;
if(++i != fre.end()) cout << "-";
}
}
}
return 0;
}