DS循环链表—约瑟夫环(Ver. I - A)
N个人坐成一个圆环(编号为1 - N),从第S个人开始报数,数到K的人出列,后面的人重新从1开始报数。问最后剩下的人的编号。
例如:N = 3,K = 2,S = 1。2号先出列,然后是1号,最后剩下的是3号。
要求使用循环链表实现。
输入
测试数据有多组
每组包括3个数N、K、S,表示有N个人,从第S个人开始,数到K出列。(1 <= N <= 10^6,1 <= K <= 10, 1 <= S <= N)
输出
出列的人的编号
输入样例1
13 3 1
3 2 1输出样例1
3 6 9 12 2 7 11 4 10 5 1 8 13
2 1 3
#include<iostream>
#include<stdio.h>
using namespace std;
//链表节点定义
class listnode
{
public:
int data;
listnode* next; //指针域
listnode()
{
data = 0;
next = NULL;
}
};
class list
{
public:
listnode* head; //头节点
int len;
list()//构造一个带头结点的空链表
{
head = new listnode();
len = 0;
}
void create(int n)
{
len = n;
listnode* tail = head; head->next = NULL;//尾部节点一开始指向头节点 然后置空习惯
int item = 0;
while (n--)
{
item++;
listnode* q = new listnode; q->next = NULL;//创建新节点q
q->data = item;
tail->next = q;//通过尾部来连接新的节点
tail = q;//连接新的节点后 连接的新的节点变成尾部
}
tail->next = head->next;
}
void yue(int n, int k, int s)
{
int i, len = n;
listnode* p = head;
for (i = 1; i < s; i++)//找到要开始的那一位,是index的作用
p = p->next;
while (len)//直到出列完成
{
if (p->next == head)//删除结点使得p->next为头节点,则p要多移一次。
p = p->next;
for (i = 1; i < k; i++)//从1开始报数,报到k-1位
{
p = p->next;
if (p->next == head)//在p向后位移的时候如果遇到头结点,多移一次。
p = p->next;
}
listnode* q = p->next;//上一个for循环找到了要删除的节点的前一位,这时候用q代表要删除的结点
cout << q->data;
p->next = q->next;//先变指针域,改为删去的节点的下一位
delete q;
len--;
if (len != 0)
{
cout << " ";
}
}
cout << endl;
}
};
int main()
{
int k, n, s, i;
while (cin >> n >> k >> s)
{
list l1;
l1.create(n);
l1.yue(n, k, s);
}
return 0;
}
DS双向链表—祖玛
祖玛是一款曾经风靡全球的游戏,其玩法是:在一条轨道上初始排列着若干个彩色珠子,其中任意三个相邻的珠子不会完全同色。此后,你可以发射珠子到轨道上并加入原有序列中。一旦有三个或更多同色的珠子变成相邻,它们就会立即消失。这类消除现象可能会连锁式发生,其间你将暂时不能发射珠子。
给定轨道上初始的珠子序列,然后是玩家所做的一系列操作。你的任务是,在各次操作之后及时计算出新的珠子序列。
输入
第一行是一个由大写字母'A'~'Z'组成的字符串,表示轨道上初始的珠子序列,不同的字母表示不同的颜色。
第二行是一个数字n,表示玩家共有n次操作。
接下来的n行依次对应于各次操作。每次操作由一个数字k和一个大写字母描述,以空格分隔。其中,大写字母为新珠子的颜色。若插入前共有m颗珠子,位置0至m-1,则k ∈ [0, m]表示新珠子嵌入在轨道上的位置。
输出
输出共n行,依次给出各次操作(及可能随即发生的消除现象)之后轨道上的珠子序列。
如果轨道上已没有珠子,则以“-”表示。
输入样例1
ACCBA
5
1 B
0 A
2 B
4 C
0 A输出样例1
ABCCBA
AABCCBA
AABBCCBA
-
A#include<iostream> using namespace std; class listnode { public: char data; int len; listnode* next; listnode* prev; }; class list { public: listnode* head; int len; list() { head = new listnode(); len = 0; } ~list() { listnode*p, * q; p = head; while (p != NULL) { q = p; p = p->next; delete q; } len = 0; head = NULL; } void create(int n, string s) { listnode* tail = head; head->len = 0; for (int i = 0; i < n; i++) { listnode* q = new listnode; q->next = NULL; q->data = s[i]; //插入字符串 tail->next = q; q->prev = tail; tail = q; head->len++; } } void display() { listnode* p = head->next; if (head->len == 0) { cout << "-"; } else { for (int i = 0; i < head->len; i++) { cout << p->data; p = p->next; } } } void insert(int k, char data) { listnode* p = head->next; if (k) //k不等于0情况 { for (int i = 1; i < k; i++) //找到第k位 { p = p->next; } listnode* q = new listnode; q->data = data; q->prev = p;//双向链表插入 找到插入位置k的前驱节点 q->next = p->next; p->next = q; //插入节点后 更新新节点q 的后继节点的前驱指针 为q q->next->prev = q; head->len++; } else if (head->len && k == 0) //链表长度不等于0且k==0 { p = head; //在开头插入新节点 listnode* q = new listnode; q->data = data; q->prev = p; q->next = p->next; p->next = q; q->next->prev = q; //插入节点后 更新新节点q 的后继节点的前驱指针 为q head->len++; } else //链表长度为0 插入后由于只有一个节点 不需要更新更新新节点q的后继节点的前驱指针 { p = head; listnode* q = new listnode; q->data = data; q->prev = p; q->next = p->next; p->next = q; head->len++; } } //祖玛 void zuma() { listnode* p = head->next; while (p) { if (p->next == NULL) { break; } if (p->data == p->prev->data && p->data == p->next->data) { int sum = 3; //用d0指向需删除最左端珠子的前继 listnode* d0 = p->prev->prev; //用d1指向需删除最右端珠子的后继 listnode* d1 = p->next->next; if (d1) while (d1->data == p->data) { if (!d1->next) { break; } d1 = d1->next; //需删除总数++ 即三个以上 sum++; } if (d1) { d0->next = d1; d1->prev = d0; } else { d0->next = NULL; } head->len -= sum; p = head->next; } else p = p->next; } } }; int main() { string s; char ch; int k; cin >> s; int n = s.length(); list l1; l1.create(n, s); int t; cin >> t; while (t--) { cin >> k >> ch; l1.insert(k, ch); l1.zuma(); l1.display(); if (t) //最后一个没有换行 { cout << endl; } } }
前驱后继(线性结构)
在双向链表中,A有一个指针指向了后继节点B,同时,B又有一个指向前驱节点A的指针。这样不仅能从链表头节点的位置遍历整个链表所有节点,也能从链表尾节点开始遍历所有节点。
对于给定的一列数据,按照给定的顺序建立双向链表,按照关键字找到相应节点,输出此节点的前驱节点关键字及后继节点关键字。
输入
第一行两个正整数n(代表节点个数),m(代表要找的关键字的个数)。
接下来输入n个整数为关键字key(数据保证关键字在数列中没有重复)。
接下来有m个要查找的关键字,每个占一行。
输出
对给定的每个关键字,输出此关键字前驱节点关键字和后继节点关键字。如果给定的关键字没有前驱或者后继,则不输出。给定关键字为每个输出占一行。
输入样例1
10 3
1 2 3 4 5 6 7 8 9 0
3
1
0
输出样例12 4
2
9#include<iostream> using namespace std; //双向链表的结点,两个指针域,一个数据域 class listnode { public: int data; listnode* pre; listnode* next; listnode() { pre = NULL; next = NULL; } }; class list { public: int len; listnode* head; //只有一个表头结点的空链表 list() { len = 0; head = new listnode(); head->next = NULL; head->pre = NULL; } void Create(int n) { int k;//k表示数据 listnode* tail = head; while (n--) { cin >> k; listnode* q = new listnode();//新建一个结点 q->data = k; tail->next = q; //尾部连接新节点 q->pre = tail; //新节点前驱指向尾部 tail = q;//新节点变成尾部 } } //寻找关键字 listnode* find(int k) { listnode* p = head; while (p->next != NULL) { p = p->next;//这个要注意逻辑,放在if前和if后是不一样的,放在后面那么最后一个数字就 //没有执行循环无法进行数据比较了 if (p->data == k) { return p; } } } void print(int k) { find(k); //在中间 if ((find(k)->next != NULL) && (find(k)->pre != head)) { cout << find(k)->pre->data << " " << find(k)->next->data << endl; } //关键字前驱指向头节点 else if (find(k)->pre == head) { cout << find(k)->next->data << endl; } else { cout << find(k)->pre->data << endl; } } }; int main() { int n, m, key; list l; cin >> n >> m; l.Create(n); while (m--) { cin >> key; l.find(key); l.print(key); } }