链表长度计算方法:详解如何高效获取链表长度

链表是什么?

  • 链表是一种用于存储数据集合的线性数据结构
  • 连续的元素通过指针连接
  • 最后一个元素指向NULL(空值)
  • 每个元素是一个独立的对象,称为节点(Node)
  • 链表中的每个节点包含两部分:数据和指向下一个节点的引用
节点
链表

如何找到链表的长度?

找到链表的长度有两种方法。

  1. 迭代方法
  2. 递归方法

使用迭代方法计算链表的长度

我们将使用链表遍历来找到链表的长度。

  • 头节点(Head)指向链表的第一个节点
  • 将计数变量(count)初始化为0
  • 将临时变量(temp)初始化为头节点(Head)
  • 每访问一个节点,计数变量的值就增加1
  • 当到达空值(null)时停止过程
  • 不要改变头节点的引用
链表长度的迭代方法

用Java编码

package com.Olivia.ds;

public class MyLinkedList {

	public class Node {

		int data;

		Node next;

	}

	public Node head;
	public Node tail;
	public int size;

	public int getFirst() throws Exception {

		if (this.size == 0) {

			throw new Exception("链表为空");

		}

		return this.head.data;
	}

	public int getLast() throws Exception {

		if (this.size == 0) {

			throw new Exception("链表为空");

		}
		return this.tail.data;
	}

	public void display() {

		Node temp = this.head;
		while (temp != null) {
			System.out.println(temp.data + " ");
			temp = temp.next;
		}
	}

	public void addFirst(int item) {

		Node nn = new Node();

		nn.data = item;
		if (this.size == 0) {
			this.head = nn;
			this.tail = nn;
			this.size = this.size + 1;

		} else {

			nn.next = this.head;

			this.head = nn;

			this.size = this.size + 1;

		}

	}

	public int length() {

		Node temp = this.head;
		int count = 0;
		while (temp != null) {
			count++;
			temp = temp.next;
		}
		return count;
	}

	public static void main(String[] args) {

		MyLinkedList ll = new MyLinkedList();

		ll.addFirst(10);

		ll.addFirst(20);

		ll.addFirst(30);

		ll.addFirst(40);

		ll.addFirst(50);

		System.out.println("链表长度为 " + ll.length());

	}

}

在C语言中编码

#include <stdio.h>

#include <stdlib.h>

/* 链表节点的结构 */

struct node {

  int data;

  struct node *next;

} *head;

void initialize(){

    head = NULL;

}

/*

在单链表前面插入一个节点

*/

void insert(int num) {

    /* 创建一个新的链表节点 */

    struct node* newNode = (struct node*) malloc(sizeof(struct node));

    newNode->data  = num;

    /* 新节点的下一个指针将指向链表的头节点 */

    newNode->next = head;

    /* 使新节点成为链表的新头节点 */

    head = newNode;

    printf("插入的元素 : %d\n", num);

}

int getLength(struct node *head){

    int length =0;

    while(head != NULL){

        head = head->next;

        length++;

    }

    return length;

}

/*

从头节点到尾节点打印链表

*/

void printLinkedList(struct node *nodePtr) {

  while (nodePtr != NULL) {

     printf("%d", nodePtr->data);

     nodePtr = nodePtr->next;

     if(nodePtr != NULL)

         printf("-->");

  }

}

int main() {

    initialize();

    /* 创建一个链表 */

    insert(8); 

    insert(3);

    insert(2);

    insert(7);

    insert(9);

    printf("\n链表\n");

    printLinkedList(head);

    printf("\n链表长度 : %d", getLength(head));

    return 0;

}

结果

迭代解决方案的输出

使用递归解决方案计算链表的长度

基础情况:

  • 最后一个节点指向空值(Null)
  • 返回0

递归情况:

  • 在每一步,将当前节点的值更新为下一个节点
  • 调用 = 1+fun(curr.next)
递归解决方案

在链表中有3个元素:LL1、LL2和LL3。当进行递归调用时,我们将观察内存堆栈中发生的情况。内存堆栈:

内存堆栈

主函数调用LL1,LL1调用LL2,LL2调用LL3,LL3调用空值。当达到空值时,我们从这里返回。0被返回给LL3,LL3向LL2返回1,LL2向LL1返回2,最后LL1向主函数返回3。

使用Java进行编码

Java实现递归方法计算链表长度

下面是一个完整的Java实现,展示了如何使用递归方法计算链表的长度。我们首先定义了一个链表类,其中包含节点类、头节点、尾节点和大小属性。

package com.Olivia.ds;

public class MyLinkedList {

    public class Node {

         int data;

         Node next;

    }

    public Node head;

    public Node tail;

    public int size;

    public int getfirst() throws Exception {

         if (this.size == 0) {

             throw new Exception("链表为空");

         }

         return this.head.data;

    }

    public int RemoveFirst() throws Exception {

         if (this.size == 0) {

             throw new Exception("链表为空");

         }

         Node temp = this.head;

         if (this.size == 1) {

             this.head = null;

             this.tail = null;

             size = 0;

         } else {

             this.head = this.head.next;

             this.size--;

         }

         return temp.data;

    }

    public void addFirst(int item) {

         Node nn = new Node();

         nn.data = item;

         if (this.size == 0) {

             this.head = nn;

             this.tail = nn;

             this.size = this.size + 1;

         } else {

             nn.next = this.head;

             this.head = nn;

             this.size = this.size + 1;

         }

    }

    public int lengthUsingRecursiveApproach (){

         return lengthUsingRecursiveApproach(this.head);

    }

    private int lengthUsingRecursiveApproach(Node curr) {

         // 自动生成的方法存根

         if (curr == null) {

             return 0;

         }

         return 1 + lengthUsingRecursiveApproach (curr.next);

    }




    public static void main(String[] args) {

         MyLinkedList ll = new MyLinkedList();

         // 向链表中插入元素

        ll.addFirst(10);

         ll.addFirst(20);

         ll.addFirst(30);

         ll.addFirst(40);

         ll.addFirst(50);

         // 链表长度

         System.out.println("递归方法计算链表长度 " + ll.lengthUsingRecursiveApproach(ll.head));

    }

}

C语言实现递归方法计算链表长度

接下来,我们看看如何在C语言中实现递归方法来计算链表的长度。C语言实现需要手动管理内存,使用malloc函数为节点分配内存空间。

#include <stdio.h>

struct Node

{

    int data;

    struct Node* next;

};
void push(struct Node** head_ref, int new_data)
{

    struct Node* new_node =  (struct Node*) malloc(sizeof(struct Node));  

    new_node->data  = new_data;  

    /* 将新节点链接到旧列表 */

    new_node->next = (*head_ref);

    (*head_ref)    = new_node;

}

int getCount(struct Node* head)

{

    // 基本情况

    if (head == NULL)

        return 0; 

    return 1 + getCount(head->next);

}

int main()

{

    struct Node* head = NULL;

    push(&head, 1);

    push(&head, 3);

    push(&head, 1);

    push(&head, 2);

    push(&head, 1);

    printf("节点数量为 %d", getCount(head));

    return 0;

}

输出结果

递归解决方案输出

时间复杂度分析

在递归和迭代解决方案中,时间复杂度均为O(N),因为我们只需要进行一次遍历来得知链表的长度。递归方法的优点是代码简洁,但缺点是可能会因为递归深度过大而导致栈溢出,特别是对于非常长的链表。在实际应用中,应根据链表的可能长度和系统资源情况选择合适的方法。

bannerAds