算法竞赛第一章-链表

P1996 约瑟夫问题

1. 动态链表

临时分配链表节点,使用完毕后释放链表节点。
优点:能及时释放空间,不使用多余内存
缺点:需要管理空间,容易出错。

#include <bits/stdc++.h>

#define int long long
#define rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define fep(i, a, b) for(int i = (a); i >= (b); --i)
#define _for(i, a, b) for(int i=(a); i<(b); ++i)
#define pii pair<int, int>
#define pdd pair<double,double>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back
#define vi vector<int>

using namespace std;

struct node{
    int data;
    node *next;
};

void solve() {
    int n,m; scanf("%d %d", &n, &m);
    node *head, *p, *now, *prev;
    head = new node; head->data = 1; head->next = NULL;
    now = head; //当前指针是头
    for(int i=2;i<=n;i++){
        p = new node; p->data = i; p->next = NULL; //p是新节点
        now->next = p; //把申请的新节点镰刀前面的链表上
        now = p; //把问指针后移一个
    }
    now->next = head;   //尾指针指向头:循环链表建立完成
    now = head, prev = head;    //从第一个开始数
    while((n--)>1){
        for(int i=1;i<m;i++){   //数到m,停下
            prev = now; //记录上一个位置,用于下面跳过第m个节点
            now = now->next;
        }
        printf("%d ", now->data); //输出第m个结点,带空格
        prev->next = now->next; //跳过这个节点
        delete now; //释放节点
        now = prev->next;   //新的一轮
    }
    printf("%d", now->data);    //打印最后一个节点,后面不带空格
    delete now; //释放最后一个节点
    return ;
}

signed main() {
//    ios::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
//	freopen("C:\\Users\\24283\\CLionProjects\\untitled2\\1.in", "r", stdin);
//    int _;
//    cin >> _;
//    while (_--)
        solve();
    return 0;
}

2. 静态链表

预先分配一段连续空间存储链表。
有两种实现方法:

  1. 定义结构体数组和动态链表的结构差不多
  2. 使用一维数组,直接在数组上进行链表操作
#include <bits/stdc++.h>

using namespace std;

const int N = 105;
struct node{ //单向链表
    int id, nextid; //单向指针
    int data;
}nodes[N];

int main() {
    int n,m;    scanf("%d%d",&n,&m);
    nodes[0].nextid = 1;
    for(int i=1;i<=n;i++){nodes[i].id=i;nodes[i].nextid=i+1;}
    nodes[n].nextid = 1; //循环链表:尾指向头
    int now = 1, prev = 1; //从第一个节点开始
    while((n--)>1){
        for(int i=1;i<m;i++){prev = now; now = nodes[now].nextid;}  //数到m停下
        printf("%d ", nodes[now].id);   //带空格打印
        nodes[prev].nextid = nodes[now].nextid; //跳过now节点,即删除now
        now = nodes[prev].nextid;   //新的now
    }
    printf("%d",nodes[now].nextid); //打印最后一个节点,后面不带空格
    return 0;
}

双向循环链表

#include <bits/stdc++.h>

using namespace std;

const int N = 105;
struct node{ //双向链表
    int id; //节点编号
    int data;
    int preid, nextid; //前一个节点,后一个节点
}nodes[N];

int main() {
    int n, m;   scanf("%d%d",&n,&m);
    nodes[0].nextid = 1;
    for(int i = 1;i<=n;i++){    //建立链表
        nodes[i].id = i;
        nodes[i].preid = i-1;
        nodes[i].nextid = i+1;
    }
    nodes[n].nextid = 1;    //循环链表:尾指头
    nodes[1].preid = n;     //循环链表:头指尾
    int now = 1;
    while((n--)>1){
        for(int i = 1;i<m;i++)  now = nodes[now].nextid;
        printf("%d ",nodes[now].id);
        int prev = nodes[now].preid, next = nodes[now].nextid;
        nodes[prev].nextid = nodes[now].nextid;
        nodes[next].preid = nodes[now].preid;
        now = next;
    }
    printf("%d", nodes[now].nextid);
    return 0;
}

3. STL list

算法竞赛或工程项目中常常使用C++ STL list。list是双向链表,由标准模板库(STL)管理,通过指针访问节点数据,高效率地删除和插入。

#include <bits/stdc++.h>

using namespace std;

const int N = 105;

int main() {
    int n, m;   cin>>n>>m;
    list<int>node;
    for(int i = 1;i<=n;++i) node.push_back(i);  //建立链表
    list<int>::iterator it = node.begin();
    while(node.size()>1){
        for(int i=1;i<m;++i){
            it++;
            if(it == node.end())    it=node.begin();
        }
        cout<<*it<<" ";
        list<int>::iterator  next = ++it;
        if(next==node.end())    next=node.begin();
        node.erase(--it);
        it = next;
    }
    cout<<*it;
    return 0;
}

练习题目

2. 两数相加
思路:模拟
需要注意的就是进位。
我的处理是第一遍加的时候先不管进位,先相加,然后再扫一遍处理进位

/**
 * 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* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* p1=l1;
        ListNode* p2=l2;
        int len1=0,len2=0;
        while(p1!=NULL) len1++, p1=p1->next;
        while(p2!=NULL) len2++, p2=p2->next;
        if(len1<len2)   swap(l1,l2);
        p2=l2;
        p1=l1;
        while(p2!=NULL){
            p1->val+=p2->val;
            p2 = p2->next;
            p1 = p1->next;
        }  
        p1=l1;
        while(p1->next!=NULL){
            p1->next->val += (p1->val)/10;
            p1->val=(p1->val)%10;
            p1=p1->next;
        }
        if(p1->val>=10){
            ListNode* now = new ListNode((p1->val)/10);
            p1->val=(p1->val)%10;
            p1->next=now;
            now->next=NULL;
        }  
        return l1;
    }
};

24. 两两交换链表中的节点


/**
 * 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* swapPairs(ListNode* head) {
        ListNode* p=head;
        int len=0;
        while(p!=NULL)  len++, p=p->next;
        if(len<=1)  return head;  
        p=head;
        while(p->next!=NULL){
            swap(p->val,p->next->val);
            if(p->next->next!=NULL) p=p->next->next;
            else{
                p=p->next;
            }
        }
        return head;
    }
};
posted @   cxy8  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
历史上的今天:
2023-04-28 4/28
点击右上角即可分享
微信分享提示