问题
已知一个带有表头结点的单链表,结点结构为(data, link),假设该链表只给出了头指针。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第k个位置上的结点。若查找成功,算法输出该结点的data域的值,并返回1;否则,只返回0。要求:
- 描述算法的基本设计思想。
- 描述算法的详细实现步骤。
解答
算法思想
定义指针p和q,初始化均指向单链表的首元结点。首先将p沿链表移动到第k个结点,而q保持不动,这样当p移动到第k+1个结点时,p和q所指的结点间隔距离k。也就是快慢指针。然后p和q同时向后移动,当p为NULL时,q所指向的结点为链表倒数第k个结点
算法步骤
- 计数器i=0,指针p和q指向首元结点。
- 从首元结点开始顺着next域遍历链表,若p为NULL,则停止遍历。
- 若i小于k,则i++;否则q指向向一个结点。
- p指向下一个结点,转步骤2
- 若i等于k,查找成功,打印p的数据域;否则查找不成功,返回0。
/*
已知一个带有表头结点的单链表,结点结构为(data, link),假设该链表只给出了头指针。
在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第k个位置上的结点。
若查找成功,算法输出该结点的data域的值,并返回1;否则,只返回0。要求:
6. 描述算法的基本设计思想。
7. 描述算法的详细实现步骤。
*/
#include <iostream>
using namespace std;
typedef struct LNode {
int data;
struct LNode *next;
}LNode, *LinkList;
void createList(LinkList &L) {
cout << "链表的元素个数:" << endl;
int n;
cin >> n;
L = new LNode;
L->next = NULL;
cout << "链表的元素:" << endl;
LinkList p = NULL, q = L;
for (int i = 0; i < n; ++i) {
p = new LNode;
cin >> p->data;
p->next = q->next;
q->next = p;
q = p;
}
}
void printList(LinkList L) {
LinkList p = L->next;
while (p) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
int findKElement(LinkList L, int k) {
LinkList p = L->next, q = p;
int i = 0;
while (p) {
if (i < k) {
i++;
} else {
q = q->next; // q落后于p
}
p = p->next;
}
if (i == k) {
// 查找成功输出结点的data域
cout << q->data << endl;
}
// 失败
return 0;
}
int main() {
LinkList L;
createList(L);
printList(L);
int k;
cin >> k;
findKElement(L, k);
return 0;
}