算法竞赛第一章-链表
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. 静态链表
预先分配一段连续空间存储链表。
有两种实现方法:
- 定义结构体数组和动态链表的结构差不多
- 使用一维数组,直接在数组上进行链表操作
#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;
}
};
/**
* 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;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 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