1、从尾到头打印双向循环链表
输入样例:
5
1 3 5 7 9
输出样例:
9 7 5 3 1
#include<bits/stdc++.h>
using namespace std;
struct node{
int data;
node *pre,*next;
};
int main(){
int n,a;
cin>>n;
cin>>a;
node *now,*head,*p;
head=new node; // 创建头节点
head->data=a; // 设置头节点的数据为a
head->next=NULL; // 头节点的next指针为空
head->pre=NULL;
now=head; // 将now指针指向头节点
for(int i=2;i<=n;i++){
cin>>a; //读入每个节点的data
p=new node; // 创建新节点
p->data=a; // 设置新节点的数据为a
p->pre=now;//新节点
p->next=NULL; // 新节点的next指针为空
now->next=p; // 将新节点连接到链表中
now=p; // 将now指针指向新节点,继续下一次循环
}
now->next=head;
head->pre=now;
for(int i=1;i<=n;i++){
cout<<(now->data)<<endl; // 输出当前节点的数据
now=now->pre; // 将now指针指向下一个节点
}
return 0;
}
2、打印链表的倒数k个节点
输入样例:
5 2
1 3 5 7 9
输出样例:
7
样例解释:
第一行:输入5个元素,输出倒数第二个元素
第二行:五个元素的值
#include<bits/stdc++.h>
using namespace std;
// 定义链表节点的结构体
struct node{
int data; // 数据域
node *pre,*next; // 前驱指针和后继指针
};
int main(){
int n,m,a;
cin>>n; // 输入链表长度
cin>>m; // 输入移动的步数
cin>>a; // 输入第一个节点的数据
node *now,*head,*p;
head=new node; // 创建头节点
head->data=a; // 设置头节点的数据为a
head->next=NULL; // 头节点的next指针为空
head->pre=NULL; // 头节点的pre指针为空
now=head; // 将now指针指向头节点
// 创建链表
for(int i=2;i<=n;i++){
cin>>a; // 输入节点的数据
p=new node; // 创建新节点
p->data=a; // 设置新节点的数据为a
p->pre=now; // 新节点的pre指针指向当前节点
p->next=NULL; // 新节点的next指针为空
now->next=p; // 将新节点连接到链表中
now=p; // 将now指针指向新节点,继续下一次循环
}
now->next=head; // 将最后一个节点的next指针指向头节点
head->pre=now; // 头节点的pre指针指向最后一个节点
// 移动到指定节点
for(int i=1;i<m;i++){
now=now->pre; // 将now指针指向前一个节点
}
cout<<(now->data)<<endl; // 输出当前节点的数据
return 0;
}
3、反转链表(单向链表反转)
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2] 输出:[2,1]
示例 3:
输入:head = [] 输出:[] 提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == nullptr || head->next == nullptr){
return head;
}
ListNode *prev = nullptr, *cur = head, *next = nullptr;
while(cur != nullptr){
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
return prev;
}
};
#include<bits/stdc++.h>
using namespace std;
struct node{
int data;
node *next;
};
int main(){
int n,a;
cin>>n>>a;
// 创建第一个节点
node *head,*pre,*now,*p;
head=new node;
head->data=a;
head->next=NULL;
now=head;
// 构建剩余的n-1个节点
for(int i=1;i<n;i++){
cin>>a;
p=new node;
p->data=a;
p->next=NULL;
now->next=p;
now=p;
}
// 创建指向反转后链表的头节点的指针
node *head2;
head2=now;
// 反转操作
for(int i=1;i<n;i++){
p=head;
for(int j=1;j<=n-i-1;j++)
p=p->next;
now->next=p;
now=now->next;
}
// 输出链表中的每个节点的数据
now=head2;
for(int i=1;i<=n;i++){
cout<<now->data<<' ';
now=now->next;
}
return 0;
}
4、有序链表的合并
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0] 提示:
- 两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
l1
和l2
均按 非递减顺序 排列
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
/*
//解法1 正常解法
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
ListNode* cur = dummyHead;
while (cur->next != NULL) {
if(cur->next->val == val) {
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
} else {
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
*/
//解法2 递归
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
if(head==nullptr){
return head;
}
head->next=removeElements(head->next,val);
if(head->val==val){
return head->next;
}
else{
return head;
}
}
};
#include<bits/stdc++.h>
using namespace std;
struct node{
int data;
node *next;
};
int main(){
int n1,n2,n;
cin>>n1>>n2;
n=n1+n2;
node *head1,*head2,*head,*p,*now,*now1,*now2;
// 建第一个链表
int a;
cin>>a;
head1=new node;
head1->data=a;
head1->next=NULL;
now=head1;
for(int i=1;i<n1;i++){
p=new node;
cin>>a;
p->data=a;
p->next=NULL;
now->next=p;
now=now->next;
}
// 建第二个链表
cin>>a;
head2=new node;
head2->data=a;
head2->next=NULL;
now=head2;
for(int i=1;i<n2;i++){
p=new node;
cin>>a;
p->data=a;
p->next=NULL;
now->next=p;
now=now->next;
}
/* 查看链表创建是否成功
now=head1;
for(int i=1;i<=n1;i++){
cout<<now->data<<' ';
now=now->next;
}
now=head2;
for(int i=1;i<=n2;i++){
cout<<now->data<<' ';
now=now->next;
}
*/
// 合并
now1=head1;now2=head2;
head=new node;
head->next=NULL;
now=head;
//不断进行比较插入,直至一个链表为空
while(now1!=NULL && now2!=NULL){
if((now1->data)<(now2->data)){
now->next=now1;
now1=now1->next;
}
else{
now->next=now2;
now2=now2->next;
}
now=now->next;
}
//直接将另一个链表中指向不为空的元素挂在now指针所指结点之后
now->next=(now1==NULL)?now2:now1;//?:三目运算表达式,当now1为空时将now2挂到now后面,否则将now1挂到now后面
// 打印
now=head->next;
while(now!=NULL){
cout<<now->data<<' ';
now=now->next;
}
return 0;
}
5、复杂链表的复制
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
返回复制链表的头节点。
用一个由 n 个节点组成的链表来表示输入/输出中的链表.每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码只接受原链表的头节点 head 作为传入参数。
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/
class Solution {
private:
unordered_map<Node*, Node*> copyMap;
public:
Node* copyRandomList(Node* head) {
if(head == nullptr) return head;
if(copyMap.find(head) != copyMap.end()) return copyMap[head];
Node* cpyHead = new Node(head->val);
copyMap[head] = cpyHead;
cpyHead->next = copyRandomList(head->next);
cpyHead->random = copyRandomList(head->random);
return copyMap[head];
}
};
6、两个链表的第一个公共节点
输入样例:
3 3
1 2 4
4 3 2
输出样例:
2
7、删除链表中的节点
有一个单链表的 head
,我们想删除它其中的一个节点 node
。
给你一个需要删除的节点 node
。你将 无法访问 第一个节点 head
。
链表的所有值都是 唯一的,并且保证给定的节点 node
不是链表中的最后一个节点。
删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:
- 给定节点的值不应该存在于链表中。
- 链表中的节点数应该减少 1。
node
前面的所有值顺序相同。node
后面的所有值顺序相同。
自定义测试:
- 对于输入,你应该提供整个链表
head
和要给出的节点node
。node
不应该是链表的最后一个节点,而应该是链表中的一个实际节点。 - 我们将构建链表,并将节点传递给你的函数。
- 输出将是调用你函数后的整个链表。
示例 1:
输入:head = [4,5,1,9], node = 5 输出:[4,1,9] 解释:指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9
示例 2:
输入:head = [4,5,1,9], node = 1 输出:[4,5,9] 解释:指定链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9
提示:
- 链表中节点的数目范围是
[2, 1000]
-1000 <= Node.val <= 1000
- 链表中每个节点的值都是 唯一 的
- 需要删除的节点
node
是 链表中的节点 ,且 不是末尾节点
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;
node->next = node->next->next;
}
};
8、队列安排(洛谷P1160)
题目描述
一个学校里老师要将班上 NN 个同学排成一列,同学被编号为 1\sim N1∼N,他采取如下的方法:
-
先将 11 号同学安排进队列,这时队列中只有他一个人;
-
2\sim N2∼N 号同学依次入列,编号为 ii 的同学入列方式为:老师指定编号为 ii 的同学站在编号为 1\sim(i-1)1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;
-
从队列中去掉 MM 个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入格式
第一行一个整数 NN,表示了有 NN 个同学。
第 2\sim N2∼N 行,第 ii 行包含两个整数 k,pk,p,其中 kk 为小于 ii 的正整数,pp 为 00 或者 11。若 pp 为 00,则表示将 ii 号同学插入到 kk 号同学的左边,pp 为 11 则表示插入到右边。
第 N+1N+1 行为一个整数 MM,表示去掉的同学数目。
接下来 MM 行,每行一个正整数 xx,表示将 xx 号同学从队列中移去,如果 xx 号同学已经不在队列中则忽略这一条指令。
输出格式
一行,包含最多 NN 个空格隔开的整数,表示了队列从左到右所有同学的编号。
输入输出样例
输入 #1
4 1 0 2 1 1 0 2 3 3
输出 #1
2 4 1
说明/提示
【样例解释】
将同学 22 插入至同学 11 左边,此时队列为:
2 1
将同学 33 插入至同学 22 右边,此时队列为:
2 3 1
将同学 44 插入至同学 11 左边,此时队列为:
2 3 4 1
将同学 33 从队列中移出,此时队列为:
2 4 1
同学 33 已经不在队列中,忽略最后一条指令
最终队列:
2 4 1
【数据范围】
对于 20\%20% 的数据,1\leq N\leq 101≤N≤10。
对于 40\%40% 的数据,1\leq N\leq 10001≤N≤1000。
对于 100\%100% 的数据,1<M\leq N\leq 10^51<M≤N≤105。
#include<bits/stdc++.h>
using namespace std;
const int mx=1e5+10;
int n,m;
struct T{
int l,r; //每个同学的“左右手”
int d; //表示同学是否输出
}t[mx]={0};
void add(int i,int k,int f) //新增同学
{
if(f==1) //左
{
t[k].r=t[i].r;
t[k].l=i;
t[i].r=k;
t[t[k].r].l=k;
}
else //右
{
t[k].r=i;
t[k].l=t[i].l;
t[i].l=k;
t[t[k].l].r=k;
}
}
int main()
{
int x,k,f;
cin>>n;
t[0].r=0,t[0].l=0;
add(0,1,1);
for (int i=2;i<=n;i++)
{
cin>>x>>f;
add(x,i,f);
}
cin>>m;
while(m--)
{
cin>>x;
t[x].d=1; //将该同学标记为不输出
}
for (int i=t[0].r;i;i=t[i].r)
{
if (t[i].d==0) //输出未标记的
cout<<i<<" ";
}
return 0;
}
9、求链表的平均值
输入样例:
5
1 3 5 7 9
输出样例:
5
#include<bits/stdc++.h>
using namespace std;
struct node{
int data;
node *next;
};
int main(){
int n=0,a=0,sum=0,cnt=0;
cin>>n>>a;
// 创建第一个节点
node *head,*now,*p;
head=new node;
head->data=a;
head->next=NULL;
now=head;
// 构建剩余的n-1个节点
for(int i=1;i<n;i++){
cin>>a;
p=new node;
p->data=a;
p->next=NULL;
now->next=p;
now=p;
}
// 输出链表中的每个节点的数据
now=head;
while(now->next!=NULL){
sum+=now->data;
cnt++;
now=now->next;
}
sum+=now->data;
cnt++;
cout<<double(sum)/cnt;
return 0;
}