daimayuan第一课栈,队列,链表
链表:
总结:没上课之前,只会用数组模拟单链表;
需要学的内容
1:结构体指针的运用;
2:队列的性质
知识点:
结构体指针:
1:c++没有自带的next,prve;
2:a[i].vaule是成员数,-> 是下一个指针;
3:结构体里套结构体指针
这个指针看似指向自身,其实不是,而是指向同一类型的不同结构。
链表和树的数据结构就都使用到此技巧。自身的结构体指针指向下一节点或者下一子树的地址。
例如:
struct Now{
int vaule;
Now *next,*prve;
}a[2001],*head,*tail;
a[i].next = h1->next;
h1->next = &a[i];
t1->next = &a[i];
t1 = &a[i];
队列的性质:
1:数组模拟队列时可以方便查找;
2:循环队列
a.判断满:循环队列的满不再是rear=front 而是改成(rear-front+maxn)%maxn。
b.入队操作: data[rear] = x; rear = (rear+1)%maxn;
总体思想就是不让rear和front的值超过maxn的大小。于是就在rear和front自增时候模maxn。
注意:空队时rear等于front,满队时必须空一个位置。
练习;205,206,301,302,303,304,305
约瑟夫问题
有 nn 个人排成一圈,从 11 到 nn 标号。从第一个人开始报数,每次数到 mm 的人出列,下一个继续从 11 开始数,依次类推,直到所有人都出列。
输出每次出列的人的编号。
输入格式
第一行,两个整数 n,mn,m。
输出格式
输出一行,包含 nn 个数,表示每次出列的人的标号。
解法一:队列
#include <bits/stdc++.h> using namespace std; int a[100001]; int tt = 1,ed = 0,cnt; int main() { int n,m; cin >> n >> m; for(int i = 1;i <= n;i ++ ) { cnt ++; if(cnt == m) { cout << i << " "; cnt = 0; continue; } ed ++; a[ed] = i; } if(tt > ed) return 0; for(int i = tt;i != ed ; i ++) { cnt ++; if(cnt == m) { cout << a[i] << " "; cnt = 0; continue; } ed ++; a[ed] = a[i]; } cout << a[ed] << '\n'; }
解法二:循环链表
#include <bits/stdc++.h> using namespace std; int n,m; struct Now{ int vaule; Now *next,*prve; }a[1001],*head,*tail; int cnt ,num; int main() { scanf("%d %d",&n,&m); head = NULL; tail = NULL; for(int i = 1;i <= n;i ++ ) { cnt ++; if(cnt == m) { printf("%d ",i); cnt = 0; continue; } a[++num].vaule = i; //cout << i << '\n'; if(head == NULL) tail = head = &a[num]; else{ tail->next = &a[num]; a[num].prve = tail; tail = &a[num]; } } if(num==0) return 0; tail->next = head; head->prve = tail; Now *p = head; // cout << num << '\n'; // num = 0; for(p;p != p->next ;p = p->next) { //p = p->next; //cout << "x" << p->vaule << '\n'; cnt ++; if(cnt == m) { printf("%d ",p->vaule); cnt = 0; //cout << p->prve->vaule <<" "<< p->next->vaule << '\n'; p->prve->next = p->next; p->next->prve = p->prve; continue; } } printf("%d\n",p->vaule); }//3 6 9 2 7 1 8 5 10 4
循环队列练习
队列是一种数据结构。现在你要支持几种操作:
-
push x
,将 xx 这个元素放到队尾。 -
pop
,表示将队首的元素删除。 -
query k
,询问从队首往后数第 kk 个元素是多少。
输入格式
第一行一个整数 mm,表示操作个数。
接下来 mm 行,每行一个上面所述的操作。
输出格式
输出若干行,对于每个查询操作,输出答案。
#include <bits/stdc++.h> using namespace std; const int size1 = 1001; int q[size1 + 1]; int n,m,front = 1,rear = size1; char str[1011]; int main() { scanf("%d",&m); //int x; for(int i = 1;i <= m;i ++) { scanf("%s",str); if(str[2] == 's') { int x; scanf("%d",&x); rear = rear % size1 + 1; q[rear] = x; } else if(str[0] == 'p') front = front % size1 + 1; else { int x ; scanf("%d",&x); if(front + x - 1 <= size1) cout << q[front + x - 1] << '\n'; else cout << q[front + x - 1 - size1] << '\n'; } } }
翻转序列
给你一个1..n
这nn个数按顺序组成的有序链表。
需要对这个链表做mm次翻转操作,每个翻转操作会给出两个数ll, rr,表示从链表的第ll个元素到第rr个元素进行翻转。
现在问你这些操作结束完的链表序列长什么样。
输入格式
第一行读入nn和mm。
后面mm行每行给出一组(l,r)(l,r),表示要翻转的区间。
输出格式
输出最后处理完成的序列。
#include <bits/stdc++.h> using namespace std; struct Now{ int vaule; Now *next,*prve; }a[2001],*head,*tail; int main() { head = NULL; tail = NULL; int n,m; cin >> n >> m; for(int i = 1;i <= n;i ++ ) { a[i].vaule = i; if(head == NULL) { head = tail = &a[i]; } else { tail -> next = &a[i]; a[i].prve = tail; tail = &a[i]; } } for(int i = 1;i <= m; i ++ ) { int l,r; cin >> l >> r; if(l == r) continue; Now *pl = head,*pr = head; for(int j = 1; j < l; j ++ ) { pl = pl -> next; } for(int j = 1;j < r; j ++ ) { pr = pr -> next; } Now *x = pl,*y = x -> next,*z,*u = pr->next,*v = pl->prve; while(x!=pr) { z = y -> next; y -> next = x; x -> prve = y; x = y; y = z; } if(head == pl) { head = pr; pr -> prve = NULL; } else { Now *p = v; p -> next = pr; pr -> prve = p; } if(tail == pr) { tail = pl; pl -> next = NULL; } else { Now *p = u; p ->prve = pl; pl ->next = p; } } for(Now *p = head ; p ;p = p->next) { cout << p->vaule << " "; } }