您现在的位置是:首页 > 技术教程 正文

单链表的多语言表达:C++、Java、Python、Go、Rust

admin 阅读: 2024-03-24
后台-插件-广告管理-内容页头部广告(手机)

单链表

是一种链式数据结构,由一个头节点和一些指向下一个节点的指针组成。每个节点包含一个数据元素和指向下一个节点的指针。头节点没有数据,只用于表示链表的开始位置。

单链表的主要操作包括:

  1. 添加元素:在链表的头部添加新元素,需要修改头节点的指针。
  2. 删除元素:删除链表中的元素,需要修改头节点和其他节点的指针。
  3. 查找元素:在链表中查找某个元素,需要遍历整个链表。
  4. 遍历链表:按照链表的顺序依次访问每个元素,需要遍历整个链表。

单链表相对于数组的优点是插入和删除元素时不需要移动其他元素,时间复杂度为O(1)。但是,在查找元素时,单链表比数组要慢,时间复杂度为O(n)。

20210817204340750.png

本文总结了 C++、Java、Python、Go、Rust 五种语言的单链表的表达:

C++

c++语言既可以用struct也能用class来表示链表节点,类可以定义方法调用相对方便。另外C++类需要自定义析构函数用以退出时释放节点所占空间,其它语言有自动的垃圾回收机制。

struct 

// 定义结构体 Node,表示链表中的节点
struct Node {
    int data;  // 节点的数据
    Node* next;  // 指向下一个节点的指针
};

// 定义类 LinkedList,表示链表
class LinkedList {
private:
    Node* head;  // 指向链表头节点的指针
}

代码:

  1. #include
  2. using namespace std;
  3. // 定义结构体 Node,表示链表中的节点
  4. struct Node {
  5. int data; // 节点的数据
  6. Node* next; // 指向下一个节点的指针
  7. };
  8. // 定义类 LinkedList,表示链表
  9. class LinkedList {
  10. private:
  11. Node* head; // 指向链表头节点的指针
  12. public:
  13. // 构造函数,初始化链表为空链表
  14. LinkedList() {
  15. head = NULL;
  16. }
  17. // 析构函数,释放链表中的所有节点
  18. ~LinkedList() {
  19. Node* curr = head;
  20. while (curr != NULL) {
  21. Node* next = curr->next;
  22. delete curr;
  23. curr = next;
  24. }
  25. }
  26. // 在链表头部添加一个新节点
  27. void add(int value) {
  28. Node* newNode = new Node;
  29. newNode->data = value;
  30. newNode->next = head;
  31. head = newNode;
  32. }
  33. // 在链表尾部添加一个新节点
  34. void push(int value) {
  35. Node* newNode = new Node;
  36. newNode->data = value;
  37. newNode->next = NULL;
  38. if (head == NULL) {
  39. head = newNode;
  40. } else {
  41. Node* curr = head;
  42. while (curr->next != NULL) {
  43. curr = curr->next;
  44. }
  45. curr->next = newNode;
  46. }
  47. }
  48. // 删除最后一个节点,并返回该节点的数据
  49. int pop() {
  50. if (head == NULL) {
  51. return -1;
  52. } else if (head->next == NULL) {
  53. int data = head->data;
  54. delete head;
  55. head = NULL;
  56. return data;
  57. } else {
  58. Node* curr = head;
  59. while (curr->next->next != NULL) {
  60. curr = curr->next;
  61. }
  62. int data = curr->next->data;
  63. delete curr->next;
  64. curr->next = NULL;
  65. return data;
  66. }
  67. }
  68. // 遍历链表,打印每个节点的数据
  69. void traverse() {
  70. Node* curr = head;
  71. while (curr != NULL) {
  72. cout << curr->data << "->";
  73. curr = curr->next;
  74. }
  75. cout << "nil" << endl;
  76. }
  77. };
  78. int main() {
  79. LinkedList list;
  80. list.traverse(); // 打印空链表 nil
  81. list.add(1); // 在链表头部添加节点 1
  82. list.traverse(); // 打印链表 1->nil
  83. list.add(2); // 在链表头部添加节点 2
  84. list.traverse(); // 打印链表 2->1->nil
  85. list.add(3); // 在链表头部添加节点 3
  86. list.traverse(); // 打印链表 3->2->1->nil
  87. list.push(4); // 在链表尾部添加节点 4
  88. list.traverse(); // 打印链表 3->2->1->4->nil
  89. list.push(5); // 在链表尾部添加节点 5
  90. list.traverse(); // 打印链表 3->2->1->4->5->nil
  91. cout << list.pop() << endl; // 删除尾节点,并输出节点数据
  92. list.traverse(); // 打印链表 3->2->1->4->nil
  93. cout << list.pop() << endl; // 删除尾节点,并输出节点数据
  94. list.traverse(); // 打印链表 3->2->1->nil
  95. return 0;
  96. }

class

// 定义类 Node,表示链表中的节点
class Node {
public:
    int data;
    Node* next;
    Node(int value) {
        data = value;
        next = NULL;
    }
};

// 定义类 LinkedList,表示链表
class LinkedList {
private:
    Node* head;  // 指向链表头节点的指针
};

代码:

  1. #include
  2. using namespace std;
  3. // 定义类 Node,表示链表中的节点
  4. class Node {
  5. public:
  6. int data;
  7. Node* next;
  8. Node(int value) {
  9. data = value;
  10. next = NULL;
  11. }
  12. };
  13. // 定义类 LinkedList,表示链表
  14. class LinkedList {
  15. private:
  16. Node* head; // 指向链表头节点的指针
  17. public:
  18. // 构造函数,初始化链表为空链表
  19. LinkedList() {
  20. head = NULL;
  21. }
  22. // 析构函数,释放链表中的所有节点
  23. ~LinkedList() {
  24. Node* curr = head;
  25. while (curr != NULL) {
  26. Node* next = curr->next;
  27. delete curr;
  28. curr = next;
  29. }
  30. }
  31. // 在链表头部添加一个新节点
  32. void add(int value) {
  33. Node* newNode = new Node(value);
  34. newNode->next = head;
  35. head = newNode;
  36. }
  37. // 在链表尾部添加一个新节点
  38. void push(int value) {
  39. Node* newNode = new Node(value);
  40. newNode->next = NULL;
  41. if (head == NULL) {
  42. head = newNode;
  43. } else {
  44. Node* curr = head;
  45. while (curr->next != NULL) {
  46. curr = curr->next;
  47. }
  48. curr->next = newNode;
  49. }
  50. }
  51. // 删除最后一个节点,并返回该节点的数据
  52. int pop() {
  53. if (head == NULL) {
  54. return -1;
  55. } else if (head->next == NULL) {
  56. int data = head->data;
  57. delete head;
  58. head = NULL;
  59. return data;
  60. } else {
  61. Node* curr = head;
  62. while (curr->next->next != NULL) {
  63. curr = curr->next;
  64. }
  65. int data = curr->next->data;
  66. delete curr->next;
  67. curr->next = NULL;
  68. return data;
  69. }
  70. }
  71. // 遍历链表,打印每个节点的数据
  72. void traverse() {
  73. Node* curr = head;
  74. while (curr != NULL) {
  75. cout << curr->data << "->";
  76. curr = curr->next;
  77. }
  78. cout << "nil" << endl;
  79. }
  80. };
  81. int main() {
  82. LinkedList list;
  83. list.traverse(); // 打印空链表 nil
  84. list.add(1); // 在链表头部添加节点 1
  85. list.traverse(); // 打印链表 1->nil
  86. list.add(2); // 在链表头部添加节点 2
  87. list.traverse(); // 打印链表 2->1->nil
  88. list.add(3); // 在链表头部添加节点 3
  89. list.traverse(); // 打印链表 3->2->1->nil
  90. list.push(4); // 在链表尾部添加节点 4
  91. list.traverse(); // 打印链表 3->2->1->4->nil
  92. list.push(5); // 在链表尾部添加节点 5
  93. list.traverse(); // 打印链表 3->2->1->4->5->nil
  94. cout << list.pop() << endl; // 删除尾节点,并输出节点数据
  95. list.traverse(); // 打印链表 3->2->1->4->nil
  96. cout << list.pop() << endl; // 删除尾节点,并输出节点数据
  97. list.traverse(); // 打印链表 3->2->1->nil
  98. return 0;
  99. }

Java

Java没有跟C或Go类似的struct结构体,只有用类class来表达。

class 

public class LinkedList {
    public class Node {
        public int data;
        public Node next;

        public Node(int value) {
            data = value;
            next = null;
        }
    }

    public LinkedList() {
        head = null;
    }
}

代码:

  1. public class LinkedList {
  2. public class Node {
  3. public int data;
  4. public Node next;
  5. public Node(int value) {
  6. data = value;
  7. next = null;
  8. }
  9. }
  10. public LinkedList() {
  11. head = null;
  12. }
  13. private Node head;
  14. // 在链表头部添加一个新的节点
  15. public void add(int value) {
  16. Node newNode = new Node(value);
  17. newNode.next = head;
  18. head = newNode;
  19. }
  20. // 在链表尾部添加一个新的节点
  21. public void push(int value) {
  22. Node newNode = new Node(value);
  23. if (head == null) {
  24. head = newNode;
  25. } else {
  26. Node curr = head;
  27. while (curr.next != null) {
  28. curr = curr.next;
  29. }
  30. curr.next = newNode;
  31. }
  32. }
  33. // 删除尾节点,并返回该节点的数据
  34. public int pop() {
  35. if (head == null) {
  36. return -1;
  37. } else if (head.next == null) {
  38. int data = head.data;
  39. head = null;
  40. return data;
  41. } else {
  42. Node curr = head;
  43. while (curr.next.next != null) {
  44. curr = curr.next;
  45. }
  46. Node tail = curr.next;
  47. curr.next = null;
  48. return tail.data;
  49. }
  50. }
  51. // 遍历链表,打印每个节点的数据
  52. public void traverse() {
  53. Node curr = head;
  54. while (curr != null) {
  55. System.out.print(curr.data + "->");
  56. curr = curr.next;
  57. }
  58. System.out.println("nil");
  59. }
  60. public static void main(String[] args) {
  61. LinkedList list = new LinkedList();
  62. list.traverse(); // 打印空链表 nil
  63. list.add(1); // 在链表头部添加节点 1
  64. list.traverse(); // 打印链表 1->nil
  65. list.add(2); // 在链表头部添加节点 2
  66. list.traverse(); // 打印链表 2->1->nil
  67. list.add(3); // 在链表头部添加节点 3
  68. list.traverse(); // 打印链表 3->2->1->nil
  69. list.push(4); // 在链表尾部添加节点 4
  70. list.traverse(); // 打印链表 3->2->1->4->nil
  71. list.push(5); // 在链表尾部添加节点 5
  72. list.traverse(); // 打印链表 3->2->1->4->5->nil
  73. System.out.println(list.pop()); // 删除尾节点,并输出节点数据
  74. list.traverse(); // 打印链表 3->2->1->4->nil
  75. System.out.println(list.pop()); // 删除尾节点,并输出节点数据
  76. list.traverse(); // 打印链表 3->2->1->nil
  77. }
  78. }

Python

Python也没有struct结构体,只能用类class来表达。而且python是动态类型语言,变量在创建时无需显式指定类型,也没有指针概念。

class 

class Node:
    def __init__(self, data):
        self.data = data  # 节点的数据
        self.next = None  # 节点的下一个指针,初始为空

class LinkedList:
    def __init__(self):
        self.head = None  # 链表的头指针,初始为空

代码:

  1. class Node:
  2. def __init__(self, data):
  3. self.data = data # 节点的数据
  4. self.next = None # 节点的下一个指针,初始为空
  5. class LinkedList:
  6. def __init__(self):
  7. self.head = None # 链表的头指针,初始为空
  8. def add(self, data):
  9. # 在链表头部插入一个新节点
  10. newNode = Node(data)
  11. newNode.next = self.head
  12. self.head = newNode
  13. def push(self, data):
  14. # 在链表尾部添加一个新节点
  15. newNode = Node(data)
  16. if self.head is None:
  17. self.head = newNode
  18. else:
  19. curr = self.head
  20. while curr.next is not None:
  21. curr = curr.next
  22. curr.next = newNode
  23. def pop(self):
  24. # 删除尾节点,并返回该节点的值
  25. if self.head is None:
  26. return None
  27. if self.head.next is None:
  28. data = self.head.data
  29. self.head = None
  30. return data
  31. curr = self.head
  32. while curr.next.next is not None:
  33. curr = curr.next
  34. tail = curr.next
  35. curr.next = None
  36. return tail.data
  37. def traverse(self):
  38. # 遍历链表,打印每个节点的数据
  39. curr = self.head
  40. while curr is not None:
  41. print(curr.data, end='->')
  42. curr = curr.next
  43. print('nil')
  44. if __name__ == '__main__':
  45. head = LinkedList() # 创建链表
  46. head.traverse() # 遍历空链表
  47. head.add(1) # 在链表头部添加节点 1
  48. head.traverse() # 遍历链表 1->nil
  49. head.add(2) # 在链表头部添加节点 2
  50. head.traverse() # 遍历链表 2->1->nil
  51. head.add(3) # 在链表头部添加节点 3
  52. head.traverse() # 遍历链表 3->2->1->nil
  53. head.push(4) # 在链表尾部添加节点 4
  54. head.traverse() # 遍历链表 3->2->1->4->nil
  55. head.push(5) # 在链表尾部添加节点 5
  56. head.traverse() # 遍历链表 3->2->1->4->5->nil
  57. print(head.pop()) # 删除尾节点,并输出节点数据
  58. head.traverse() # 打印链表 3->2->1->4->nil
  59. print(head.pop()) # 删除尾节点,并输出节点数据
  60. head.traverse() # 打印链表 3->2->1->nil

Golang

Go没有class类,使用结构体 struct 来代替类。结构体可以包含字段(成员变量),并且可以定义方法(成员函数)来操作结构体的数据。

struct

type Node struct {
    data int
    next *Node
}

type LinkedList struct {
    head *Node
}

// 创建一个新的节点
func new(value int) *Node {
    return &Node{
        data: value,
        next: nil,
    }
}

代码:

  1. package main
  2. import "fmt"
  3. type Node struct {
  4. data int
  5. next *Node
  6. }
  7. type LinkedList struct {
  8. head *Node
  9. }
  10. // 创建一个新的节点
  11. func new(value int) *Node {
  12. return &Node{
  13. data: value,
  14. next: nil,
  15. }
  16. }
  17. // 在链表头部添加一个新节点
  18. func (list *LinkedList) add(value int) {
  19. newNode := new(value)
  20. newNode.next = list.head
  21. list.head = newNode
  22. }
  23. // 在链表尾部添加一个新节点
  24. func (list *LinkedList) push(value int) {
  25. newNode := new(value)
  26. if list.head == nil {
  27. list.head = newNode
  28. } else {
  29. curr := list.head
  30. for curr.next != nil {
  31. curr = curr.next
  32. }
  33. curr.next = newNode
  34. }
  35. }
  36. // 删除尾节点,并返回该节点的值
  37. func (list *LinkedList) pop() int {
  38. if list.head == nil {
  39. return -1
  40. } else if list.head.next == nil {
  41. data := list.head.data
  42. list.head = nil
  43. return data
  44. } else {
  45. curr := list.head
  46. for curr.next.next != nil {
  47. curr = curr.next
  48. }
  49. tail := curr.next
  50. curr.next = nil
  51. return tail.data
  52. }
  53. }
  54. // 遍历链表,打印每个节点的数据
  55. func (list *LinkedList) traverse() {
  56. curr := list.head
  57. for curr != nil {
  58. fmt.Printf("%d->", curr.data)
  59. curr = curr.next
  60. }
  61. fmt.Println("nil")
  62. }
  63. func main() {
  64. list := LinkedList{}
  65. list.traverse() // 打印空链表 nil
  66. list.add(1) // 在链表头部添加节点 1
  67. list.traverse() // 打印链表 1->nil
  68. list.add(2) // 在链表头部添加节点 2
  69. list.traverse() // 打印链表 2->1->nil
  70. list.add(3) // 在链表头部添加节点 3
  71. list.traverse() // 打印链表 3->2->1->nil
  72. list.push(4) // 在链表尾部添加节点 4
  73. list.traverse() // 打印链表 3->2->1->4->nil
  74. list.push(5) // 在链表尾部添加节点 5
  75. list.traverse() // 打印链表 3->2->1->4->5->nil
  76. fmt.Println(list.pop()) // 删除尾节点,并打印数据
  77. list.traverse() // 打印链表 3->2->1->4->nil
  78. fmt.Println(list.pop()) // 删除尾节点,并打印数据
  79. list.traverse() // 打印链表 3->2->1->nil
  80. }

Rust

Rust中也没有类的概念,但它提供了结构体 struct 和 trait 两种重要的机制来实现面向对象的编程风格。结构体用于定义数据结构,而 trait 则用于定义方法集合。

另外在Rust中,一般不使用unsafe指针std::ptr来操作链表,而是 Option 类型来表示链表指针,它代表的值可以存在(Some)也可以不存在(None)。Option 类型被广泛用于处理可能为空的值,以避免出现空指针异常。

struct

struct Node {
    data: i32,
    next: Option>,
}

impl Node {
    fn new(value: i32) -> Node {
        Node { data: value, next: None }
    }
}

struct LinkedList {
    head: Option>,
}

impl LinkedList {
    fn new() -> LinkedList {
        LinkedList { head: None }
    }
}

代码:

  1. struct Node {
  2. data: i32,
  3. next: Option<Box>,
  4. }
  5. impl Node {
  6. fn new(value: i32) -> Node {
  7. Node { data: value, next: None }
  8. }
  9. }
  10. struct LinkedList {
  11. head: Option<Box>,
  12. }
  13. impl LinkedList {
  14. fn new() -> LinkedList {
  15. LinkedList { head: None }
  16. }
  17. // 在链表头部添加一个新节点
  18. fn add(&mut self, value: i32) {
  19. let mut new_node = Box::new(Node::new(value));
  20. new_node.next = self.head.take();
  21. self.head = Some(new_node);
  22. }
  23. // 在链表尾部添加一个新节点
  24. fn push(&mut self, value: i32) {
  25. let new_node = Box::new(Node::new(value));
  26. let mut curr = &mut self.head;
  27. while let Some(node) = curr {
  28. curr = &mut node.next;
  29. }
  30. *curr = Some(new_node);
  31. }
  32. // 删除尾节点,并返回该节点的数据
  33. fn pop(&mut self) -> Option<i32> {
  34. if self.head.is_none() {
  35. return None;
  36. }
  37. if self.head.as_ref().unwrap().next.is_none() {
  38. let data = self.head.take().unwrap().data;
  39. return Some(data);
  40. }
  41. let mut curr = self.head.as_mut().unwrap();
  42. while curr.next.as_ref().unwrap().next.is_some() {
  43. curr = curr.next.as_mut().unwrap();
  44. }
  45. let data = curr.next.take().unwrap().data;
  46. Some(data)
  47. }
  48. // 遍历链表,打印每个节点的数据
  49. fn traverse(&self) {
  50. let mut curr = &self.head;
  51. while let Some(node) = curr {
  52. print!("{}->", node.data);
  53. curr = &node.next;
  54. }
  55. println!("nil");
  56. }
  57. }
  58. fn main() {
  59. let mut list = LinkedList::new();
  60. list.traverse(); // 打印空链表 nil
  61. list.add(1); // 在链表头部添加节点 1
  62. list.traverse(); // 打印链表 1->nil
  63. list.add(2); // 在链表头部添加节点 2
  64. list.traverse(); // 打印链表 2->1->nil
  65. list.add(3); // 在链表头部添加节点 3
  66. list.traverse(); // 打印链表 3->2->1->nil
  67. list.push(4); // 在链表尾部添加节点 4
  68. list.traverse(); // 打印链表 3->2->1->4->nil
  69. list.push(5); // 在链表尾部添加节点 5
  70. list.traverse(); // 打印链表 3->2->1->4->5->nil
  71. println!("{}", list.pop().unwrap()); // 删除尾节点,并输出节点数据
  72. list.traverse(); // 打印链表 3->2->1->4->nil
  73. println!("{}", list.pop().unwrap()); // 删除尾节点,并输出节点数据
  74. list.traverse(); // 打印链表 3->2->1->nil
  75. }

struct unsafe

struct Node {
    data: i32,
    next: *mut Node,
}

impl Node {
    fn new(value: i32) -> Node {
        Node { data: value, next: std::ptr::null_mut() }
    }
}

struct LinkedList {
    head: *mut Node,
}

impl LinkedList {
    fn new() -> LinkedList {
        LinkedList { head: std::ptr::null_mut() }
    }
}

代码:

  1. struct Node {
  2. data: i32,
  3. next: *mut Node,
  4. }
  5. impl Node {
  6. fn new(value: i32) -> Node {
  7. Node { data: value, next: std::ptr::null_mut() }
  8. }
  9. }
  10. struct LinkedList {
  11. head: *mut Node,
  12. }
  13. impl LinkedList {
  14. fn new() -> LinkedList {
  15. LinkedList { head: std::ptr::null_mut() }
  16. }
  17. fn add(&mut self, value: i32) {
  18. let mut new_node = Box::new(Node::new(value));
  19. new_node.next = self.head;
  20. self.head = Box::into_raw(new_node);
  21. }
  22. fn push(&mut self, value: i32) {
  23. let new_node = Box::new(Node::new(value));
  24. let mut curr = &mut self.head;
  25. while !(*curr).is_null() {
  26. curr = unsafe { &mut (**curr).next };
  27. }
  28. *curr = Box::into_raw(new_node);
  29. }
  30. fn pop(&mut self) -> Option<i32> {
  31. if self.head.is_null() {
  32. return None;
  33. }
  34. let mut curr = self.head;
  35. let mut prev = std::ptr::null_mut();
  36. while unsafe { !(*curr).next.is_null() } {
  37. prev = curr;
  38. curr = unsafe { (*curr).next };
  39. }
  40. let data = unsafe { Box::from_raw(curr) }.data;
  41. if prev.is_null() {
  42. self.head = std::ptr::null_mut();
  43. } else {
  44. unsafe { (*prev).next = std::ptr::null_mut(); }
  45. }
  46. Some(data)
  47. }
  48. fn traverse(&self) {
  49. let mut curr = self.head;
  50. while !curr.is_null() {
  51. unsafe {
  52. print!("{}->", (*curr).data);
  53. curr = (*curr).next;
  54. }
  55. }
  56. println!("nil");
  57. }
  58. fn cleanup(&mut self) {
  59. let mut curr = self.head;
  60. while !curr.is_null() {
  61. let next = unsafe { (*curr).next };
  62. unsafe { Box::from_raw(curr) };
  63. curr = next;
  64. }
  65. }
  66. }
  67. fn main() {
  68. let mut list = LinkedList::new();
  69. list.traverse(); // 打印空链表 nil
  70. list.add(1);
  71. list.traverse();
  72. list.add(2);
  73. list.traverse();
  74. list.add(3);
  75. list.traverse();
  76. list.push(4);
  77. list.traverse();
  78. list.push(5);
  79. list.traverse();
  80. println!("{}", list.pop().unwrap());
  81. list.traverse();
  82. println!("{}", list.pop().unwrap());
  83. list.traverse();
  84. list.cleanup();
  85. }

cleanup()相当于析构函数,用于释放链表所占空间。


以上所有示例代码的输出都相同:

nil
1->nil
2->1->nil
3->2->1->nil
3->2->1->4->nil
3->2->1->4->5->nil
5
3->2->1->4->nil
4
3->2->1->nil

其中,Rust的节点值有点特殊,使用了Some类型。比如:

使用println!("{:?}", list.pop());  不需要pop()后面的.unwrap(),返回Some(n);当链表为空时,直接返回None。


标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索