
/* 给一个非循环双向链表增加一个freq值,用以表示它的访问频率,每访问一次freq就+1,然后需要将该链表按照非增的顺序 排列,同时最近访问的节点排在相同频度节点的前面,以便使频繁访问的节点总是靠近表头。试编写符合上述要求的Locate(L,x) 函数,该运算为函数过程,返回找到节点的地址,类型为指针型。 分析: 这道题咋一看很唬人,还引入了一个新概念,其实并不难,拆分开来其实就是 查找+排序;我们需要先找到我们要访问的节点 ,更改它的freq值,然后按照freq值的大小从表头寻找插入位置,这样便完成了一次locate操作。*/struct Link { int data; struct Link *pre; struct Link *next; int freq;};#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>void locate(Link *h,int num) { int flag = 0;//找到标志 struct Link *pre=h, *p = h->next, *t,*preQ=h,*q; while (p) { if (p->data==num) {//如果找到 flag = 1;//表示找到 p->freq++;//freq+1 t = p;//将该节点保存起来 if (p->next) { pre->next = p->next;//将该节点抠出来 p->next->pre = pre; } else { pre->next = NULL;//这里也要注意,如果我们查找的节点是最后一个节点,我们要将next指向NULL,不然之后遍历时会出问题 } q = h->next;//这里需要注意,q应该始终指向改变了的首节点,之前我在定义时去指定,会出现bug while (q) {//进行排序 if (t->freq >= q->freq) {//当找到的节点的freq大于等于当前遍历节点时,插入 t->next = q; q->pre = t; preQ->next = t; t->pre = preQ; break; } preQ = q; q = q->next; } break; } pre = p; p = p->next; } if (!flag) { printf("未找到该元素,序列不做改变"); }}int main() { int n, data,num; struct Link *head = (struct Link *)malloc(sizeof(struct Link)); head->next = NULL; head->pre = NULL; struct Link *p = head; printf("请输入节点个数:n="); scanf("%d", &n); for (int i = 0; i < n; i++) { printf("请输入第%d个节点值:", i + 1); scanf("%d", &data); struct Link *newP = (struct Link*)malloc(sizeof(struct Link)); newP->data = data; newP->pre = p; newP->freq = 0; p->next = newP; p = newP; } p->next = NULL; do { printf("请输入要查找的值,输入9999代表结束:num="); scanf("%d",&num); if (num == 9999)continue;//如果num=9999,跳入下一次循环 locate(head,num); //p = head->next; printf("调整后链表为:\n"); while (p) { printf("%d ",p->data); p = p->next; } } while (num!=9999); return 0;}