📜  为什么链表是在堆内存而不是栈内存上实现的?

📅  最后修改于: 2022-05-13 01:57:09.316000             🧑  作者: Mango

为什么链表是在堆内存而不是栈内存上实现的?

先决条件:

链表数据结构
Stack vsHeap 内存分配

链表是一种线性数据结构,其中元素不存储在连续的内存位置。链表中的元素使用指针链接。它是在堆内存而不是堆栈内存上实现的。本文讨论了其背后的原因。

堆栈与堆内存

计算机的内存分为堆内存段和栈内存段。栈内存段比较小,主要用于递归等操作或goto语句等控制跳转语句。由于堆栈段的大小很小,它不用于深度递归级别,因为它可能会引发堆栈溢出错误。

另一方面,链表的主要优点是在需要时动态扩展自身,而不用担心内存消耗。这就是为什么首选堆来存储链表对象的原因。

为什么链表不存储在堆栈内存中?

为什么不能用堆栈内存创建链表的问题是由于范围规则和堆栈上的自动内存管理。链表的基本思想是根据节点的内存地址将节点链接在一起。如果每个节点都是在堆栈上创建的,那么这些节点将在超出范围后被删除,因此即使用户保留指向其内存地址的指针,假设它们不会被其他东西覆盖也是不安全的。

链表也可以在栈内存上实现。下面是在栈内存中创建链表的 C++ 实现:

C++
// C++ program to implement
// linked list in stack
#include 
using namespace std;
 
// Structure of the linked list
struct Node {
    int data;
    struct Node* next;
 
    // Constructor
    Node(int x)
    {
        data = x;
        next = NULL;
    }
}* head = NULL;
 
// Function to print the linked list
void printLinkedList(Node* head)
{
    struct Node* temp = head;
 
    // Traversing linked list
    while (temp) {
        cout << temp->data << " ";
        temp = temp->next;
    }
}
 
// Driver code
int main()
{
    // Creation of linked list in stack
    struct Node first = Node(1);
    struct Node second = Node(2);
    struct Node third = Node(3);
    struct Node fourth = Node(4);
 
    head = &first;
 
    // 1 -> 2 -> 3 -> 4
    first.next = &second;
    second.next = &third;
    third.next = &fourth;
    fourth.next = NULL;
 
    // Printing the elements of
    // a linked list
    printLinkedList(head);
 
    return 0;
}


Java
// Java program to implement
// linked list in stack
 
import java.util.*;
 
class GFG{
 
// Structure of the linked list
static class Node {
    int data;
    Node next;
 
    // Constructor
    Node(int x)
    {
        data = x;
        next = null;
    }
};
static Node head = null;
 
// Function to print the linked list
static void printLinkedList(Node head)
{
    Node temp = head;
 
    // Traversing linked list
    while (temp!=null) {
        System.out.print(temp.data+ " ");
        temp = temp.next;
    }
}
 
// Driver code
public static void main(String[] args)
{
    // Creation of linked list in stack
    Node first = new Node(1);
    Node second = new  Node(2);
    Node third = new Node(3);
    Node fourth = new Node(4);
 
    head = first;
 
    // 1.2.3.4
    first.next = second;
    second.next = third;
    third.next = fourth;
    fourth.next = null;
 
    // Printing the elements of
    // a linked list
    printLinkedList(head);
 
}
}
 
// This code contributed by shikhasingrajput


C#
// C# program to implement
// linked list in stack
using System;
using System.Collections.Generic;
 
public class GFG{
 
  // Structure of the linked list
  class Node {
    public int data;
    public Node next;
 
    // Constructor
    public Node(int x)
    {
      data = x;
      next = null;
    }
  };
  static Node head = null;
 
  // Function to print the linked list
  static void printList(Node head)
  {
    Node temp = head;
 
    // Traversing linked list
    while (temp!=null) {
      Console.Write(temp.data+ " ");
      temp = temp.next;
    }
  }
 
  // Driver code
  public static void Main(String[] args)
  {
 
    // Creation of linked list in stack
    Node first = new Node(1);
    Node second = new  Node(2);
    Node third = new Node(3);
    Node fourth = new Node(4);
 
    head = first;
 
    // 1.2.3.4
    first.next = second;
    second.next = third;
    third.next = fourth;
    fourth.next = null;
 
    // Printing the elements of
    // a linked list
    printList(head);
 
  }
}
 
// This code is contributed by shikhasingrajput


Javascript


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Structure of the linked list
struct Node {
    int data;
    struct Node* next;
 
    Node(int x)
    {
        data = x;
        next = NULL;
    }
}* head = NULL;
 
// Function to return the head pointer
// of the created linked list
Node* CreateLinkedList()
{
    struct Node first = Node(1);
    struct Node second = Node(2);
    struct Node third = Node(3);
    struct Node fourth = Node(4);
 
    head = &first;
 
    // 1->2->3->4
    first.next = &second;
    second.next = &third;
    third.next = &fourth;
    fourth.next = NULL;
 
    return head;
}
 
// Function to print the linked list
void printLinkedList(Node* head)
{
    struct Node* temp = head;
 
    // Traversing linked list
    while (temp) {
        cout << temp->data << " ";
        temp = temp->next;
    }
}
 
// Driver Code
int main()
{
    struct Node* head = CreateLinkedList();
    printLinkedList(head);
    return 0;
}


Java
// Java program to implement
// the above approach
 
import java.util.*;
 
class GFG{
 
// Structure of the linked list
static class Node {
    int data;
    Node next;
 
    Node(int x)
    {
        data = x;
        next = null;
    }
}
static Node head = null;
 
// Function to return the head pointer
// of the created linked list
static Node CreateLinkedList()
{
    Node first = new Node(1);
    Node second = new Node(2);
    Node third = new Node(3);
    Node fourth = new Node(4);
 
    head = first;
 
    // 1.2.3.4
    first.next = second;
    second.next = third;
    third.next = fourth;
    fourth.next = null;
 
    return head;
}
 
// Function to print the linked list
static void printLinkedList(Node head)
{
    Node temp = head;
 
    // Traversing linked list
    while (temp!=null) {
        System.out.print(temp.data+ " ");
        temp = temp.next;
    }
}
 
// Driver Code
public static void main(String[] args)
{
    Node head = CreateLinkedList();
    printLinkedList(head);
}
}
 
// This code is contributed by 29AjayKumar


C#
// C# program to implement
// the above approach
 
using System;
 
public class GFG{
 
  // Structure of the linked list
  class Node {
    public int data;
    public Node next;
 
    public Node(int x)
    {
      data = x;
      next = null;
    }
  }
  static Node head = null;
 
  // Function to return the head pointer
  // of the created linked list
  static Node CreateList()
  {
    Node first = new Node(1);
    Node second = new Node(2);
    Node third = new Node(3);
    Node fourth = new Node(4);
 
    head = first;
 
    // 1.2.3.4
    first.next = second;
    second.next = third;
    third.next = fourth;
    fourth.next = null;
 
    return head;
  }
 
  // Function to print the linked list
  static void printList(Node head)
  {
    Node temp = head;
 
    // Traversing linked list
    while (temp != null) {
      Console.Write(temp.data + " ");
      temp = temp.next;
    }
  }
 
  // Driver Code
  public static void Main(String[] args)
  {
    Node head = CreateList();
    printList(head);
  }
}
 
// This code is contributed by shikhasingrajput


C++
// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Structure of the linked list
struct Node {
    int data;
    struct Node* next;
};
struct Node* head = NULL;
 
// Function to create nodes of
// the linked list
void CreateLinkedList(int new_data)
{
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = new_data;
    new_node->next = head;
    head = new_node;
}
 
// Function to print the linked list
void printLinkedList()
{
    struct Node* temp;
    temp = head;
 
    // Traversing linked list
    while (temp != NULL) {
        cout << temp->data << " ";
        temp = temp->next;
    }
}
 
// Driver Code
int main()
{
    CreateLinkedList(1);
    CreateLinkedList(2);
    CreateLinkedList(3);
    CreateLinkedList(4);
    printLinkedList();
    return 0;
}


Java
// Java program to implement
// the above approach
import java.util.*;
public class GFG{
 
// Structure of the linked list
static class Node {
    int data;
    Node next;
};
static Node head = null;
 
// Function to create nodes of
// the linked list
static void CreateLinkedList(int new_data)
{
    Node new_node = new Node();
    new_node.data = new_data;
    new_node.next = head;
    head = new_node;
}
 
// Function to print the linked list
static void printLinkedList()
{
    Node temp;
    temp = head;
 
    // Traversing linked list
    while (temp != null) {
        System.out.print(temp.data+ " ");
        temp = temp.next;
    }
}
 
// Driver Code
public static void main(String[] args)
{
    CreateLinkedList(1);
    CreateLinkedList(2);
    CreateLinkedList(3);
    CreateLinkedList(4);
    printLinkedList();
}
}
 
// This code is contributed by 29AjayKumar


C#
// C# program to implement
// the above approach
using System;
using System.Collections.Generic;
 
public class GFG {
 
  // Structure of the linked list
  public class Node {
    public int data;
    public Node next;
  };
 
  static Node head = null;
 
  // Function to create nodes of
  // the linked list
  static void CreateList(int new_data) {
    Node new_node = new Node();
    new_node.data = new_data;
    new_node.next = head;
    head = new_node;
  }
 
  // Function to print the linked list
  static void printList() {
    Node temp;
    temp = head;
 
    // Traversing linked list
    while (temp != null) {
      Console.Write(temp.data + " ");
      temp = temp.next;
    }
  }
 
  // Driver Code
  public static void Main(String[] args) {
    CreateList(1);
    CreateList(2);
    CreateList(3);
    CreateList(4);
    printList();
  }
}
 
// This code is contributed by umadevi9616


Javascript


输出:

堆栈上的链表实现不起作用的条件:

如果我们将创建链表的逻辑写在一个单独的函数中,将打印链表的元素的逻辑写在一个单独的函数中,上面的代码将无法工作。以下是上述概念的 C++ 实现:

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Structure of the linked list
struct Node {
    int data;
    struct Node* next;
 
    Node(int x)
    {
        data = x;
        next = NULL;
    }
}* head = NULL;
 
// Function to return the head pointer
// of the created linked list
Node* CreateLinkedList()
{
    struct Node first = Node(1);
    struct Node second = Node(2);
    struct Node third = Node(3);
    struct Node fourth = Node(4);
 
    head = &first;
 
    // 1->2->3->4
    first.next = &second;
    second.next = &third;
    third.next = &fourth;
    fourth.next = NULL;
 
    return head;
}
 
// Function to print the linked list
void printLinkedList(Node* head)
{
    struct Node* temp = head;
 
    // Traversing linked list
    while (temp) {
        cout << temp->data << " ";
        temp = temp->next;
    }
}
 
// Driver Code
int main()
{
    struct Node* head = CreateLinkedList();
    printLinkedList(head);
    return 0;
}

Java

// Java program to implement
// the above approach
 
import java.util.*;
 
class GFG{
 
// Structure of the linked list
static class Node {
    int data;
    Node next;
 
    Node(int x)
    {
        data = x;
        next = null;
    }
}
static Node head = null;
 
// Function to return the head pointer
// of the created linked list
static Node CreateLinkedList()
{
    Node first = new Node(1);
    Node second = new Node(2);
    Node third = new Node(3);
    Node fourth = new Node(4);
 
    head = first;
 
    // 1.2.3.4
    first.next = second;
    second.next = third;
    third.next = fourth;
    fourth.next = null;
 
    return head;
}
 
// Function to print the linked list
static void printLinkedList(Node head)
{
    Node temp = head;
 
    // Traversing linked list
    while (temp!=null) {
        System.out.print(temp.data+ " ");
        temp = temp.next;
    }
}
 
// Driver Code
public static void main(String[] args)
{
    Node head = CreateLinkedList();
    printLinkedList(head);
}
}
 
// This code is contributed by 29AjayKumar

C#

// C# program to implement
// the above approach
 
using System;
 
public class GFG{
 
  // Structure of the linked list
  class Node {
    public int data;
    public Node next;
 
    public Node(int x)
    {
      data = x;
      next = null;
    }
  }
  static Node head = null;
 
  // Function to return the head pointer
  // of the created linked list
  static Node CreateList()
  {
    Node first = new Node(1);
    Node second = new Node(2);
    Node third = new Node(3);
    Node fourth = new Node(4);
 
    head = first;
 
    // 1.2.3.4
    first.next = second;
    second.next = third;
    third.next = fourth;
    fourth.next = null;
 
    return head;
  }
 
  // Function to print the linked list
  static void printList(Node head)
  {
    Node temp = head;
 
    // Traversing linked list
    while (temp != null) {
      Console.Write(temp.data + " ");
      temp = temp.next;
    }
  }
 
  // Driver Code
  public static void Main(String[] args)
  {
    Node head = CreateList();
    printList(head);
  }
}
 
// This code is contributed by shikhasingrajput

解释:

上面的代码给出了 SEGMENTATION FAULT 的判断。其背后的原因是,在堆栈内存中创建链表的过程中,函数创建的所有对象都会随着函数结束或返回时弹出堆栈帧而消失。请参阅本文以了解每当函数结束时弹出堆栈帧的原因。

为什么链表存储在堆内存中?

在链表中,当需要存储更多数据时,我们可以在运行时使用 malloc 或 C/C++ 中的新函数分配内存。所以动态内存分配会从堆区保留大小,因此,堆内存中存储了一个链表。
如果需要在堆栈区域中存储链表,则在不使用 malloc 或新函数的情况下实现链表。

下面是展示如何在堆内存中实现链表而不抛出分段错误错误的 C++ 程序:

C++

// C++ program to implement
// the above approach
#include 
using namespace std;
 
// Structure of the linked list
struct Node {
    int data;
    struct Node* next;
};
struct Node* head = NULL;
 
// Function to create nodes of
// the linked list
void CreateLinkedList(int new_data)
{
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = new_data;
    new_node->next = head;
    head = new_node;
}
 
// Function to print the linked list
void printLinkedList()
{
    struct Node* temp;
    temp = head;
 
    // Traversing linked list
    while (temp != NULL) {
        cout << temp->data << " ";
        temp = temp->next;
    }
}
 
// Driver Code
int main()
{
    CreateLinkedList(1);
    CreateLinkedList(2);
    CreateLinkedList(3);
    CreateLinkedList(4);
    printLinkedList();
    return 0;
}

Java

// Java program to implement
// the above approach
import java.util.*;
public class GFG{
 
// Structure of the linked list
static class Node {
    int data;
    Node next;
};
static Node head = null;
 
// Function to create nodes of
// the linked list
static void CreateLinkedList(int new_data)
{
    Node new_node = new Node();
    new_node.data = new_data;
    new_node.next = head;
    head = new_node;
}
 
// Function to print the linked list
static void printLinkedList()
{
    Node temp;
    temp = head;
 
    // Traversing linked list
    while (temp != null) {
        System.out.print(temp.data+ " ");
        temp = temp.next;
    }
}
 
// Driver Code
public static void main(String[] args)
{
    CreateLinkedList(1);
    CreateLinkedList(2);
    CreateLinkedList(3);
    CreateLinkedList(4);
    printLinkedList();
}
}
 
// This code is contributed by 29AjayKumar

C#

// C# program to implement
// the above approach
using System;
using System.Collections.Generic;
 
public class GFG {
 
  // Structure of the linked list
  public class Node {
    public int data;
    public Node next;
  };
 
  static Node head = null;
 
  // Function to create nodes of
  // the linked list
  static void CreateList(int new_data) {
    Node new_node = new Node();
    new_node.data = new_data;
    new_node.next = head;
    head = new_node;
  }
 
  // Function to print the linked list
  static void printList() {
    Node temp;
    temp = head;
 
    // Traversing linked list
    while (temp != null) {
      Console.Write(temp.data + " ");
      temp = temp.next;
    }
  }
 
  // Driver Code
  public static void Main(String[] args) {
    CreateList(1);
    CreateList(2);
    CreateList(3);
    CreateList(4);
    printList();
  }
}
 
// This code is contributed by umadevi9616

Javascript


输出:

堆栈与堆内存中的链表

S No.Linked List in Stack MemoryLinked List in Heap Memory
1Linked list in stack will get access to relatively small memory that is not dynamically expandable.Linked list in heap will get access to dynamically expandable memory.
2Each node created in the linked list and stored in the stack will get linked deleted after it goes out of scope.There is a need to free the memory for the node to be deleted.
3If there is a need to store a linked list in the stack area then implement a linked list without using malloc or a new function.If there is a need to store linked list in heap then implement linked list using malloc or new function.
4Linked list nodes created in the stack cannot be accessed after the the scope of function ends.Linked list nodes created and stored in heap memory can be accessed after the scope of the function ends.