双向循环链表locate(L,x)以节点freq排序问题

问题:

设有一个双向循环链表,每个结点中除有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;
        }
    }
}
  • 9
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值