(1)方法1:首先遍历一遍单链表,求出整个单链表的长度n,然后将倒数第k个,转换为正数第n-k个,接下去遍历一次就可以得到结果。但该算法需要对链表进行两次遍历,第一次遍历用于求解单链表的长度,第二次遍历用于查找正数第n-k个元素。
(2)方法2:如果沿着从头到尾的方向,从链表中的某个元素开始,遍历k个元素后刚好达到链表尾,那么该元素就是要找的倒数第k个元素。根据这一性质,可以设计如下算法:从头节点开始,一次对链表的每一个节点元素进行这样的测试,遍历k个元素,查看是否到达链表尾,直到找到那个倒数第k个元素为止。这种方法将对同一批元素进行反复多次的遍历,对于链表中的大部分元素而言,都要遍历k个元素,如果链表的长度为n,该算法的时间复杂度为O(kn)级,效率太低。
(3)方法3:有一种更高效的方式,只需要一次遍历即可查找到倒数第k个元素。由于单链表只能从头到尾依次访问链表的各个节点,所以如果要找链表的倒数第k个元素,也只能从头到尾进行遍历查找。在查找过程中,设置两个指针,让其中一个指针比另一个指针先前移k-1步,然后两个指针同时往前移动。循环直到先行的指针指为NULL时,另一个指针所指的位置就是所要找的位置。如下所示:
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
} NODE;
// 尾插法创建单链表(带头节点)
NODE *createEnd(int arr[], int len)
{
NODE *head = (NODE *)malloc(sizeof(NODE)); // 生成头节点
head->next = NULL;
NODE *end = head; // 尾指针初始化
for (int i = 0; i < len; i++) {
NODE *p = (NODE *)malloc(sizeof(NODE)); // 为每个数组元素建立一个节点
p->data = arr[i];
end->next = p; // 将节点p插入到终端节点之后
end = p;
}
end->next = NULL; // 单链表建立完毕,将终端节点的指针域置空
return head;
}
// 找出单链表中的倒数第k个元素
NODE *search_last_k(NODE *head, int k)
{
NODE *p1 = head;
NODE *p2 = head;
for (int i = 0; i < k; i++) {
p2 = p2->next;
}
while (p2 != NULL) {
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
// 单链表打印
void print(NODE *head)
{
if (head == NULL) return;
NODE *p = head->next;
while (p != NULL) {
printf("%d\n", p->data);
p = p->next;
}
}
int main(void)
{
int arr[] = {1,2,3,4,5,6,7};
int len = sizeof(arr)/sizeof(int);
NODE *head = createEnd(arr, len);
print(head);
printf("-----------\n");
NODE *temp_k = search_last_k(head, 3);
printf("%d\n",temp_k->data);
return 0;
}
时间: 2024-11-10 06:32:47