DS单链表 基础例题
A.单链表的类实现
用C++语言和类实现单链表,含头结点
属性包括:data数据域、next指针域
操作包括:插入、删除、查找
注意:单链表不是数组,所以位置从1开始对应首结点,头结点不放数据
输入
输出
样例输入
样例输出
题解
#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表示指向两个结点的指针
输入
输出
样例输入
样例输出
题解
将两个节点的前驱和后继交换即可
#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)
输入
输出
样例输入
样例输出
题解
这里给出两个方法,完整代码中给出的是方法一
方法一:直接链接节点
这里是合并得到新的头节点,但是原来的节点没有改变。就是说如果原链表变化,该新链表中的节点数据也会发生变化。
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容器或静态链表。不用考虑宿舍分配和交回不成功的情况。
输入
输出
样例输入
样例输出
题解
通过结构 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;
}