链表 - Part I

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

 

  • 优点:可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
  • 缺点:链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

 

  • 一般链表中只有一个表头
  • 元素不是顺序存储的,不能随机访问
  • 元素相互依赖,串联而成

 

构造一个链表:

首先创建两个模板类,一个用来创建链表节点对象,另一个用来创建链表:

 1 template <typename Type> class Node {
 2 public:
 3     Type data;
 4     Node<Type> *next;
 5  
 6     Node(const Type &_data) {
 7         data = _data;
 8         next = nullptr;
 9     }
10 };
11  
12 template <typename Type> class LinkedList {
13 private:
14     Node<Type> *head;
15 public:
16     LinkedList() {
17         head = nullptr;
18     }
19     ~LinkedList() {
20         Node<Type> *current_node = head;
21         while (current_node != nullptr) {
22             Node<Type> *delete_node = current_node;
23             current_node = current_node->next;
24             delete delete_node;
25         }
26     }
27 }

接下来给链表类添加如下的函数操作:

 

插入函数 insert(node, index),将node插入到链表中下标为index的位置:

实现方法:

1. 遍历到链表中要插入的位置的前一位。

2. 令待插入结点的 next 指针指向插入位置的当前结点。

3. 令插入位置之前的当前结点的 next 指针指向待插入结点。

 1 bool insert(Node<Type> * node, int index) {
 2         if (head == nullptr) {
 3             if (index != 0) {
 4                 return false;
 5             }
 6             head = node;
 7             return true;
 8         }
 9         if (index == 0) {
10             node -> next = head;
11             head = node;
12             return true;
13         }
14         Node<Type> * current_node = head;
15         int count = 0;
16         while (current_node -> next != nullptr && count < index - 1) {
17             current_node = current_node -> next;
18             count ++;
19         }
20         if (count == index - 1) {
21             node -> next = current_node -> next;
22             current_node -> next = node;
23             return true;
24         }
25         return false;
26     }

遍历函数output(),从头结点开始通过当前结点的指针找到下一节点直至表尾,并输出所有结点的值:

实现方法:

1. 定义一个用于遍历的变量,初始指向头结点。

2. 输出遍历变量所在结点的值,并更新遍历变量为当前结点的下一个结点。

3. 重复操作 2,直到遍历完所有结点。

 1 void output() {
 2         if (head == nullptr) {
 3             return;
 4         }
 5         Node<Type> * current_node = head;
 6         while (current_node != nullptr) {
 7             cout << current_node -> data << " ";
 8             current_node = current_node -> next;
 9         }
10         cout << endl;
11     }

删除函数delete_node(index),删除链表中下标为index的元素:

实现方法:

1. 从表头遍历找到要删除的位置的前一位。

2. 令删除位置前一个结点的next指针指向待删除位置后一个结点。

3. 删除结点。

 1 bool delete_node(int index) {
 2         if (head == nullptr) {
 3             return false;
 4         }
 5         Node<Type> * current_node = head;
 6         int count = 0;
 7         if (index == 0) {
 8             head = head -> next;
 9             delete current_node;
10             return true;
11         }
12         while (current_node -> next != nullptr && count < index - 1) {
13             current_node = current_node -> next;
14             count ++;
15         }
16         if (current_node -> next != nullptr && count == index - 1) {
17             Node<Type> * delete_node = current_node -> next;
18             current_node -> next = delete_node -> next;
19             delete delete_node;
20             return true;
21         }
22         return false;
23     }

翻转函数reverse(),翻转整个链表:

实现方法:

1. 定义一个用于遍历的指针,初始指向头结点后一个结点。

2. 让头结点的 next 指针置空。

3. 从当前遍历指针所指的结点开始遍历链表,将遍历到的结点 next 指针指向头结点。遍历过程中借助另外一个指针保存下一个遍历到的结点。

4. 重复步骤 3 直至表尾,此时新的链表就是原链表反转后的链表。

 1 void reverse() {
 2         if (head == nullptr) {
 3             return;
 4         }
 5         Node<Type> * current_node, * next_node;
 6         current_node = head -> next;
 7         head -> next = nullptr;
 8         while (current_node != nullptr) {
 9             next_node = current_node -> next;
10             current_node -> next = head;
11             head = current_node;
12             current_node = next_node;
13         }
14     }

 

posted @ 2017-09-08 09:49  Xehanort_Hajime  阅读(141)  评论(0)    收藏  举报