问题:
设有一个双向循环链表,每个结点中除有prior, data和next三个域外,还增设了一个访问频度域freq。在链表启用之前,频度域freq的值均初始化为零,而每当对链表进行一次locate(L,x)的操作后,被访问的结点(即元素值等于x的结点)中的频度域freq的值便增1,同时调整链表中结点之间的次序,使其按访问频度非递增的次序顺序排列,以便始终保持被频繁访问的结点总是靠近表头结点。试编写符合上述要求的locate操作的算法。
解决:
首先Locate问题不难解决,问题在于如何把freq更改后的节点按不增序排列。
如果把这个问题想像成排序问题就比较复杂了。这个问题的背景是freq均为0的情况下,每进行一次Locate、就更改一次序列。
那么问题就简化了啊,只要在每一次Locate后,对于被索引的节点,先将其从链表中拿出(不free),然后遍历链表,寻找到第一个不大于它的节点freq,插入到其前面。由于一开始freq均为0,所以就达成了目的。
代码:
/*Lab1_3_19281158
*
*题目:Locat以及更改序列
*/
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<malloc.h>
using namespace std;
#define EleType int
//双向循环链表节点
typedef struct LNode
{
EleType data;
int freq = 0; //记录被访问的频度
struct LNode* prior;
struct LNode* next;
}*Link, * Position;
typedef struct
{
Link head, tail;
int len;
Link current;
}LinkList;
int a[100000] = {
0 };
LinkList List;
void InitList(LinkList& L);
void MakeNode(Link& p, EleType e);
void Transition(LinkList& L, Link& f);
void OutputList(LinkList L);
void LocateChange(LinkList& L, EleType x);
int main()
{
int n;
int n_target;
EleType target;
//输入数据
cout << "输入链表元素个数:" << endl;
cin >> n;
cout << "输入元素:" << endl;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
cout << "输入Locat操作的次数:" << endl;
cin >> n_target;
//创建
InitList(List);
for (int i = 0; i < n; i++)
{
MakeNode(List.tail, a[i]);
}
//执行操作
for (int i = 0; i < n_target; i++)
{
cout << "目标" << i + 1 << ":" << endl;
cin >> target;
LocateChange(List, target);
OutputList(List);
}
return 0;
}
void InitList(LinkList& L)
{
List.head = (Link)malloc(sizeof(LNode));
if (!List.head)
{
exit(0);
}
List.tail = List.head;
List.len = 0;
List.current = List.head;
}
void MakeNode(Link& p, EleType e)
{
Link q = (Link)malloc(sizeof(LNode));
if (!q)
{
exit(1);
}
q->data = e;
q->next = List.head; //循环链表
q->prior = p;
q->freq = 0;
p->next = q;
List.tail = q;
List.head->prior = List.tail;
List.len++;
}
void Transition(LinkList& L, Link& f)
{
Link p = L.head->next;
//f拿出原节点
while (p != L.head)
{
if (p == f)
{
if (p == L.tail)
{
L.tail = p->prior;
}
p->prior->next = p->next;
p->next->prior = p->prior;
break;
}
else
{
p = p->next;
}
}
//在相应位置插入节点
Link m = L.head->next;
while (m != L.head)
{
if (m->freq <= f->freq)
{
f->next = m;
f->prior = m->prior;
m->prior->next = f;
m->prior = f;
break;
}
else
{
m = m->next;
}
}
//如果都比之大,作为tail加入
if (m == L.head)
{
L.tail->next = f;
L.head->prior = f;
f->prior = L.tail;
f->next = L.head;
L.tail = f;
}
}
void OutputList(LinkList L)
{
Link p = L.head;
while (p != L.tail)
{
cout << p->next->data << " ";
p = p->next;
}
cout << endl;
}
void LocateChange(LinkList& L, EleType x)
{
Link p = L.head->next;
while (p != L.head)
{
if (p->data == x)
{
p->freq++;
Transition(List, p);
p = p->next;
}
else
{
p = p->next;
}
}
}