数据结构:双向循环链表
存储结构:链式存储
选择链式存储原因:节点要用freq域,用数组太麻烦
实现的操作:插入节点、访问节点、被访问节点需要往链表头移动
需要注意的地方:题中没有写清楚:当两个节点的prec相同时,该用什么顺序排列
比如下面这种情况:
假设用(val,freq)代表一个节点
假设原始链表为这样:
(头)→(1,2)→(2,1)→(3,0)→(4,0)
那么,访问了一次4后,节点4的freq从0变成了1,需要往前移动,移动之后的链表有下面两种可能性:
第一种(AC):(头)→(1,2)→ (2,1)→(4,1) →(3,0)
第二种(PE):(头)→(1,2)→ (4,1)→(2,1) →(3,0)
这就涉及到比较frec时,是<,还是<=的问题
根据本人测试,第一种是AC的,第二种是PE(我也不知道为啥不是WA?)
#include <iostream>
#include <stdlib.h>
#include <climits>
using namespace std;
typedef struct node
{
char val;
int freq;
struct node *pre;
struct node *next;
}*List;
int main()
{
//初始化链表
List L = (List)malloc(sizeof(struct node));
L->freq = INT_MAX; //头节点的freq改成最大值,这样方便之后比较
List tail = L; //指向尾节点的指针,初始为头节点自己
List tmp;
//输入链表
int m,n;
cin>>m>>n;
for(int i=0; i<m; i++) {
tmp = (List)malloc(sizeof(struct node));
cin>>tmp->val;
tmp->freq = 0; //新节点,freq=0
tmp->pre = tail; //插在队尾
tail->next = tmp; //插在队尾
tmp->next = NULL; //next暂时指向空
tail = tmp; //尾指针指向新节点
}
L->pre = tail; //头节点的pre指向尾节点
tail->next = L; //尾节点的next指向尾节点
//输入n个被访问的节点
char x;
List loc;
while(n--) {
cin>>x;
//从前往后遍历,找节点x
for(tmp=L->next; tmp!=L; tmp=tmp->next) {
//如果找到了
if(tmp->val == x) {
//freq++,并先将这个节点从链表中取出来
tmp->freq++;
tmp->pre->next = tmp->next;
tmp->next->pre = tmp->pre;
//从这个节点原本的位置一路向前找
loc=tmp->pre;
while(loc->freq < tmp->freq) //如果按照第一种情况处理,这里是<,会AC
loc=loc->pre; //如果按照第二种情况处理,这里是<=,会PE
//退出while循环后,loc->freq 肯定>= tmp->freq
//也就是需要把tmp插到loc后面
tmp->pre = loc;
tmp->next = loc->next;
loc->next = tmp;
tmp->next->pre = tmp;
break;
}
}
}
//输出
for(tmp=L->next; tmp->next!=L; tmp=tmp->next)
cout<<tmp->val<<' ';
cout<<tmp->val<<endl;
return 0;
}