链表--物理存储上非连续的线性表(习题)

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 和要给出的节点 nodenode 不应该是链表的最后一个节点,而应该是链表中的一个实际节点。
  • 我们将构建链表,并将节点传递给你的函数。
  • 输出将是调用你函数后的整个链表。

示例 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,他采取如下的方法:

  1. 先将 11 号同学安排进队列,这时队列中只有他一个人;

  2. 2\sim N2∼N 号同学依次入列,编号为 ii 的同学入列方式为:老师指定编号为 ii 的同学站在编号为 1\sim(i-1)1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;

  3. 从队列中去掉 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;
}

  • 28
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值