单向链表
单向链表(Singly Linked List)是一种常见的数据结构,它由一系列节点(Node)构成,每个节点包含数据(value)和一个指向下一个节点的指针(next)。每个节点只知道它指向的下一个节点,而无法直接访问前一个节点。
一个单向链表经常包含一个指向第一个节点的头指针(head),以便能够快速访问到链表的起始位置。链表的最后一个节点的指针通常为空(null),表示链表的结束。
特点
单向链表的特点:
-
单向性:单向链表中的节点只有一个指针,指向下一个节点,而无法直接访问前一个节点。这意味着只能从头开始遍历链表,无法进行反向操作。
-
动态性:单向链表的大小可以根据需要动态增长或缩小,因为每个节点的指针可以在运行时被修改。
-
灵活性:由于节点之间由指针连接,可以通过调整指针的指向来插入、删除或重新排序节点,而无需移动大量的数据。
-
存储效率:相对于数组,单向链表不需要一块连续的内存空间来存储,它可以更灵活地利用内存。但是,由于每个节点需要额外的指针空间,可能会占用更多的内存。
-
插入和删除的效率:在链表的开头或结尾插入和删除节点的操作具有较高的效率,只需要修改指针的指向。但是,在链表的中间插入或删除节点需要遍历链表来找到正确的位置,效率较低。
-
随机访问的效率:由于无法直接访问前一个节点,要访问链表中的特定节点,需要从头开始遍历链表,直到找到目标节点。因此,链表的随机访问效率相对较低。
实现
数据结构
节点
class Node {
public:
T val;
Node *next;
};
T val:存储节点数据的变量。
Node *next:指向下一个节点的指针。
其他
Node *head;
int siz;
Node *head:头指针
int siz:链表元素个数
结构图
实现功能
1、末尾添加元素:void add(T t);
2、头部添加元素(list第一个位置):void add_first(T t);
3、指定位置添加元素:void add(int index, T t);
4、查找元素t:int find(T &t);
5、获取index位置的元素:T get(int index) ;
6、删除元素t:void remove(T &t);
7、翻转list(交换数据):void reverse();
8、翻转list(重构):void reverse2();
C++实现
方法声明以及部分实现
/**
* 单向链表single_list
*/
#ifndef LIST_SINGLE_LIST_H
#define LIST_SINGLE_LIST_H
#include <iostream>
template<typename T>
class SingleList {
public:
class Node {
public:
T val;
Node *next;
};
void add(T t);
void add_first(T t);
void add(int index, T t);
int find(T &t) {// 查找元素t,返回index
Node *t_h = head->next;
int i = 0;
while (t_h != nullptr) {
if (t_h->val == t) return i;
t_h = t_h->next;
i++;
}
return -1;
};
T get(int index) { // 获取index位置的元素
Node *t = head->next;
for (int i = 0; i < index; i++) {
t = t->next;
}
return t->val;
}
void remove(T &t) {// 删除元素t
if (!siz) return;
Node *t_h = head;
Node *th_pre;
while ((th_pre = t_h) != nullptr && t_h->next != nullptr && (t_h = t_h->next)->val != t) {}
if (t_h->val != t) return; // 如果最后一个节点也不等于t删除失败
th_pre->next = t_h->next;
delete t_h;
t_h = nullptr;
siz--;
}
// 反转 (结构不变交换数据)
void reverse();
// 反转(重构)
void reverse2();
void print() { // 打印
Node *t = head->next;
while (t != nullptr) {
std::cout << t->val << " ";
t = t->next;
}
std::cout << std::endl;
}
SingleList() {
head = new Node();
}
private:
Node *head;
int siz;
};
#endif //LIST_SINGLE_LIST_H
核心实现
尾部添加元素
/**
* 尾部添加元素
* @brief SingleList::add
* @param t
*/
template<typename T>
void SingleList<T>::add(T t){ // 尾部添加
Node *newNode = new Node();
newNode->val = t;
Node *t_h = head;
while (t_h->next != nullptr) {
t_h = t_h->next;
}
t_h->next = newNode;
siz++;
};
头部添加元素
/**
* 头部添加元素
* @brief SingleList::add_first
* @param t
*/
template<typename T>
void SingleList<T>::add_first(T t){// 头部添加
Node *newNode = new Node();
newNode->val = t;
newNode->next = head->next;
head->next = newNode;
siz++;
};
指定位置添加元素
/**
* 在位置index处添加元素
* @brief SingleList::add
* @param index
* @param t
*/
template<typename T>
void SingleList<T>::add(int index, T t){// 指定位置添加
if (index < 0) return add_first(t);
if (index > siz - 1) return add(t);
Node *newNode = new Node();
newNode->val = t;
Node *t_h = head->next; // index位置原始节点
Node *th_pre = head; // index-1位置节点
for (int i = 0; i < index; i++) {
th_pre = t_h;
t_h = t_h->next;
}
th_pre->next = newNode;
newNode->next = t_h;
siz++;
}
翻转(交换数据)
// 反转 (结构不变交换数据)
template<typename T>
void SingleList<T>::reverse() {
if(siz < 2) return;
int half_siz = siz >> 1;
Node *t = head;
for (int i = 0; i < half_siz; i++) {
t = t->next;
Node *x = t;
for (int j = i; j < siz - 1 - i; j++) { // 找到与t对称的节点
x = x->next;
}
// 交换值
T tp = x->val;
x->val = t->val;
t->val = tp;
}
}
反转(重构)
template<typename T>
void SingleList<T>::reverse2(){
if(siz<2) return;
Node *curr_pre = head->next; // curr_pre始终指向原始数组的第一个元素
Node *curr = curr_pre == nullptr ? nullptr : curr_pre->next;
Node *curr_next = curr == nullptr ? nullptr : curr->next;
// 每次循环将curr放到链表头部,curr_pre->next 指向剩余链表的头部
while(curr_next != nullptr){
curr->next = head->next;
curr_pre->next = curr_next;
head->next = curr;
curr = curr_next;
curr_next = curr_next->next;
}
// 最后将末尾元素放到链表首部
curr->next = head->next;
curr_pre->next = nullptr;
head->next = curr;
}
测试
代码
#include "single_list.h"
int main() {
SingleList<int> singleList = SingleList<int>();
singleList.add(4);
singleList.add_first(6);
singleList.add(1,5);
singleList.print();
singleList.reverse();
singleList.print();
singleList.add(9);
singleList.reverse2();
singleList.print();
std::cout << singleList.get(1) << std::endl;
std::cout << singleList.find(4) << std::endl;
singleList.remove(4);
singleList.print();
singleList.remove(10);
singleList.print();
singleList.remove(6);
singleList.print();
}
运行结果
6 5 4
4 5 6
9 6 5 4
6
3
9 6 5
9 6 5
9 5