链表(三)
20.设头指针为工的带有表头结点的非循环双向链表, 其每个结点中除有pred(前驱指针).data(数据)和next(后继指针)城外, 还有一个访问频度域freq.在链表被启用前, 其值均初始化为零。每当在链表中进行一次Locate(L, x)运算时令元素值为×的结点中freq域的值增1, 并使此链表中结点保持按访问频度非增(递减)的顺序排列, 同时最近访问的结点排在频度相同的结点前面, 以便使频繁访问的结点总是靠近表头。试编写符合上述要求的LocateL, x)运算的算法, 该运算为函数过程, 返回找到结点的地址, 类型为指针型。
DLinkList Locate(DLinkList& L, ElemType x) {
DNode* p = L->next, * q;
while (p && p->data != x)
p = p->next;
if (!p) {
printf('不存在结点为x');
exit(0);
}
else {
p->freq++;
//断链
if (p->next != NULL) {
p->next->pre = p;
p->pre->next = p->next;
}
q = p->pre;
while (q != L && q->fre <= p->fre) {
q = q->pre;
}
q->next->pre = p;
p->next = q->next;
q->next = p;
p->pre = q;
}
return p;
}
21.已知一个带有表头结点的单链表,结点结构为 【data,link】。假设该链表只给出了头指针list.在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第七个位置上的结点(k为正整数)。若查找成功,算法输出该结点的data域的值,并返回1;否则,只返回0,要求:1)描述算法的基本设计思想
2)描述算法的详细实现步骤。
3)根据设计思想和实现步骤,采用程序设计语言描述算法(使用C.C++或Java语言实现),关键之处请给出简要注释。
typedef int ElemType
typedef struct LNode {
ElemType data;
struct LNode* link;
}LNode,*LinkList;
int search_k(LinkList list, int k) {
LNode* p=list->link, * q=list->link;
int count;
while (p != NULL) {
if (count < k) count++;
else q = q->link;
p = p->link;
}
if(count<k)
return 0
else {
printf("%d", q->data);
return 1;
}
}
typedef struct Node {
char data;
struct Node* next;
}SNode;
int listlen(SNode* head) {
int len = 0;
while (head->next != NULL) {
len++;
}
return len;
}
SNode* find_addr(SNode* str1, SNode* str2) {
int m, n;
SNode* p, * q;
m = listlen(str1);
n = listlen(str2);
for (p = str1; m > n; m--)
p = p->next;
for (q = str2; m < n; n--)
q = q->next;
while (p->next != NULL && p->next != q->next) {
p = p->next;
q = q->next;
}
return p->next;
}
typedef struct node {
int data;
struct node* link;
}Node,*PNode;
void func(Pnode h, int n) {
PNode p = h, r;
int* q, m;
q = (int*)malloc(sizeof(int) * (n + 1));
for (int i = 0; i < n + 1; i++)
*(q + i) = 0;
while (p->link != NULL) {
m = p->link->data > 0 ? p->link->data : -p->link->data;
if (*(q + m) == 0) {
*(q + m) = 1;
p = p->link;
}
else {
r = p->link;
p->link = r->link;
free(r);
}
}
free(q);
}
24.设计一个算法完成:判断一个链表是否有环,如果有,找出环的入口点并返回,否则返回NULL。
则有2 (a+x)=atn*rtx,即a-n*r-x。显然从头结点到环的入口点的距离等于n倍的环长减去环的入口点到相遇点的距离。因此可设置两个指针,一个指向head,一个指向相遇点,两个指针同步移动(均为一次走一步),相遇点即为环的入口点。
LNode* FindLoopStart(LNode* head) {
LNode* fast = head, * slow = head;
while (slow != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) break; //查找到相遇点
}
if (slow == NULL || fast->next == NULL)
return NULL;
LNode* p1 = head, * p2 = slow;
while (p1 != p2) {
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
void change_list(NODE* h) {
NODE* p, * q, * r, * s;
p = q = h;
while (q->next != NULL) {
p = p->next;
q = q->next;
if (q->next != NULL)q = q->next;
}
q = p->next; //p中间结点
p->next = NULL;
while (q != NULL) { //p看作头结点
r = q->next;
q->next = p->next;
p->next = q;
q = r;
}
s = h->next;
q = p->next;
p->next = NULL;
while (q != NULL) {
r = q->next;
q->next = s->next;
s->next = q;
s = q->next;
q = r;
}
}