链表是非常常见的一种数据结构,尤其是在一些操作系统中。
链表常见的操作有插入节点、删除节点、访问节点等。
本文实现了单向链表、双向链表的设计,并提供了可直接运行的C++代码,此外还说明了使用C语言在实现上的差异
本文所使用的图取自代码随想录
链表类型
-
单链表
-
双向链表
-
循环链表
链表的存储方式
各个节点分布在内存的不同地址空间上,通过指针串联在一起
单链表的定义
struct ListNode {
int val; // 节点上存储的元素
ListNode *next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(NULL) {} // 节点的构造函数
};
链表的操作
-
删除节点
-
添加节点
与数组对比
插入/删除(时间复杂度) | 查询(时间复杂度) | 使用场景 | |
---|---|---|---|
数组 | O(n) | O(1) | 数据量固定,频繁查询,较少增删 |
链表 | O(1) | O(n) | 数据量不固定,频繁增删,较少查询 |
移除链表元素
struct node {
int value;
node *next;
node(int x) : value(x), next(nullptr) {}
};
node *removeElement(node *head, int val){
node *dummyHead = new node(0);
dummyHead->next = head;
node *cur = dummyHead;
while(cur->next != NULL){
if(cur->next->value == val){
node *tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else{
cur = cur->next;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
链表设计
class MyList{
public:
struct node{
int value;
node *next;
node(int initValue):value(initValue), next(nullptr){}
};
MyList(){
_dummyHead = new node(0);
_size = 0;
}
// 获取第index个结点的数值
int get(int index){
if(index > (_size-1) || index < 0){
// throw out_of_range("index out of range!");
cout << "index out of range!————return INT32_MAX = " << INT32_MAX << endl;
return INT32_MAX;
}
node *cur = _dummyHead->next;
while(index){
cur = cur->next;
index--;
}
return cur->value;
}
// 在链表最前面插入一个节点
void addAtHead(int value){
node *newNode = new node(value);
newNode->next = _dummyHead->next;
_dummyHead->next = newNode;
_size++;
}
// 在链表最后面插入一个元素
void addAtTail(int value){
node *newNode = new node(value);
node *cur = _dummyHead;
while(cur->next != nullptr){
cur = cur->next;
}
cur->next = newNode;
_size++;
}
// 在第index个节点之前插入一个节点
void addAtIndex(int index, int value){
if(index > _size){
return;
}
if(index < 0){
index = 0;
}
node *newNode = new node(value);
node *cur = _dummyHead;
while(index != 0){
cur = cur->next;
index--;
}
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
// 删除第index个节点
void deleteAtIndex(int index){
if(index < 0 || index >= _size){
return;
}
node *cur = _dummyHead;
while(index != 0){
cur = cur->next;
index--;
}
node *tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
tmp = nullptr;
_size--;
}
// 打印链表
void printList(){
node *cur = _dummyHead;
while(cur->next != nullptr){
cout << cur->next->value;
cur = cur->next;
if(cur->next){
cout << "->";
}
}
cout << endl;
}
private:
int _size;
node *_dummyHead;
};
单独实现插入节点
struct node{
int value;
node *next;
node(int initValue):value(initValue), next(nullptr){}
};
void addAtIndex(node *&head, int index, int value){
node *dummyHead = new node(0);
dummyHead->next = head;
node *cur = dummyHead;
int size = 0;
while(cur->next != nullptr){
size++;
cur = cur->next;
}
if(index < 0){
index = 0;
}
if(index > size){
delete dummyHead;
cout << "index is invalid" << endl;
return;
}
cur = dummyHead;
while(index){
cur = cur->next;
index--;
}
node *newNode = new node(value);
newNode->next = cur->next;
cur->next = newNode;
size++;
head = dummyHead->next;
delete dummyHead;
}
使用C语言实现,与C++基本一致,只不过我们要自己定义结点的创建函数,并且new/delete要对应转换为malloc/free
typedef struct node{
int value;
struct node *next;
}node;
node *createNode(int value){
node *newNode = (node *)malloc(sizeof(struct node));
newNode->value = value;
newNode->next = NULL;
return newNode;
}
void addAtIndex(node **head, int index, int value){
node *dummyHead = createNode(0);
dummyHead->next = *head;
int size = 0;
node *cur = dummyHead;
while(cur->next != NULL){
cur = cur->next;
size++;
}
if(index < 0)index=0;
if(index > size){
free(dummyHead);
return;
}
cur = dummyHead;
while(index){
cur = cur->next;
index--;
}
node *newNode = createNode(value);
newNode->next = cur->next;
cur->next = newNode;
*head = dummyHead->next;
free(dummyHead);
}
双向链表设计
class MyDualList{
public:
struct node{
int value;
node *next;
node *prev;
node(int initValue):value(initValue), next(nullptr), prev(nullptr){}
};
MyDualList(){
_dummyHead = new node(0);
_dummyTail = new node(0);
_size = 0;
_dummyHead->next = _dummyTail;
_dummyTail->prev = _dummyHead;
}
int get(int index){
if(index < 0 || index >= _size){
return -1;
}
node *cur = _dummyHead->next;
while(index){
cur = cur->next;
index--;
}
return cur->value;
}
void addAtHead(int value){
node *newNode = new node(value);
newNode->next = _dummyHead->next;
_dummyHead->next->prev = newNode; // 跟单链表一致,只是在指针换向时多考虑一个prev指针
_dummyHead->next = newNode;
newNode->prev = _dummyHead; //
_size++;
}
void addAtTail(int value){
node *newNode = new node(value);
// 这里设计的双向链表,与单向链表相比,末尾节点会指向_dummyTail,基于此可以像单向链表一样写
// 不过从另一个角度来说,我们的尾插可以看作在_dummyTail之前插入一个节点
_dummyTail->prev->next = newNode;
newNode->prev = _dummyTail->prev;
newNode->next = _dummyTail;
_dummyTail->prev = newNode;
_size++;
}
void addAtIndex(int index, int value){
if(index < 0)index=0;
if(index > _size)return;
node *cur = _dummyHead;
while(index){
cur = cur->next;
index--;
}
node *newNode = new node(value);
newNode->next = cur->next;
cur->next->prev = newNode;
cur->next = newNode;
newNode->prev = cur;
_size++;
}
void deleteAtIndex(int index){
if(index < 0 || index >= _size)return;
node *cur = _dummyHead;
while(index){
cur = cur->next;
index--;
}
node *tmp = cur->next;
cur->next = cur->next->next;
cur->next->prev = cur;
delete tmp;
_size--;
}
void printListForward(){
node *cur = _dummyHead;
while(cur->next != _dummyTail){
cout << cur->next->value;
cur = cur->next;
if(cur->next != _dummyTail){
cout << "->";
}
}
cout << endl;
}
void printListReverse(){
node *cur = _dummyTail;
while(cur->prev != _dummyHead){
cout << cur->prev->value;
cur = cur->prev;
if(cur->prev != _dummyHead){
cout << "<-";
}
}
cout << endl;
}
private:
int _size = 0;
node *_dummyHead, *_dummyTail;
};
测试部分
-
函数测试——添加与移除链表元素
/* C++ */ #include<iostream> using namespace std; struct node { int value; node *next; node(int x) : value(x), next(NULL) {} }; void printList(node *head){ node *dummyHead = new node(0); dummyHead->next = head; node *cur = dummyHead; while(cur->next){ cout << cur->next->value; cur = cur->next; if(cur->next){ cout << "->"; } } cout << endl; } void removeElement(node *&head, int val){ node *dummyHead = new node(0); dummyHead->next = head; node *cur = dummyHead; while(cur->next != NULL){ if(cur->next->value == val){ node *tmp = cur->next; cur->next = cur->next->next; delete tmp; } else{ cur = cur->next; } } head = dummyHead->next; delete dummyHead; } void addAtIndex(node *&head, int index, int value){ node *dummyHead = new node(0); dummyHead->next = head; node *cur = dummyHead; int size = 0; while(cur->next != nullptr){ size++; cur = cur->next; } if(index < 0){ index = 0; } if(index > size){ delete dummyHead; cout << "index is invalid" << endl; return; } cur = dummyHead; while(index){ cur = cur->next; index--; } node *newNode = new node(value); newNode->next = cur->next; cur->next = newNode; size++; head = dummyHead->next; delete dummyHead; dummyHead = nullptr; } int main(void){ node *head = new node(0); addAtIndex(head, 1, 1); addAtIndex(head, 2, 2); addAtIndex(head, 3, 3); addAtIndex(head, 4, 4); addAtIndex(head, 5, 5); cout << "the LinkedList is:" << endl; printList(head); removeElement(head, 2); printList(head); return 0; }
/* C */
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
int value;
struct node *next;
}node;
node *createNode(int value){
node *newNode = (node *)malloc(sizeof(struct node));
newNode->value = value;
newNode->next = NULL;
return newNode;
}
void printList(node *head){
node *dummyHead = createNode(0);
dummyHead->next = head;
node *cur = dummyHead;
while(cur->next){
printf("%d", cur->next->value);
cur = cur->next;
if(cur->next){
printf("->");
}
}
printf("\n");
}
void addAtIndex(node **head, int index, int value){
node *dummyHead = createNode(0);
dummyHead->next = *head;
int size = 0;
node *cur = dummyHead;
while(cur->next != NULL){
cur = cur->next;
size++;
}
if(index < 0)index=0;
if(index > size){
free(dummyHead);
return;
}
cur = dummyHead;
while(index){
cur = cur->next;
index--;
}
node *newNode = createNode(value);
newNode->next = cur->next;
cur->next = newNode;
*head = dummyHead->next;
free(dummyHead);
}
void removeElement(node **head, int val){
node *dummyHead = createNode(0);
dummyHead->next = *head;
node *cur = dummyHead;
while(cur->next != NULL){
if(cur->next->value == val){
node *tmp = cur->next;
cur->next = cur->next->next;
free(tmp);
}
else{
cur = cur->next;
}
}
*head = dummyHead->next;
free(dummyHead);
}
int main(void){
node *head = createNode(0);
addAtIndex(&head, 1, 1);
addAtIndex(&head, 2, 2);
addAtIndex(&head, 3, 3);
addAtIndex(&head, 4, 4);
addAtIndex(&head, 5, 5);
printf("the LinkedList is:\n");
printList(head);
removeElement(&head, 0);
printList(head);
return 0;
}
-
链表设计测试
#include<iostream> using namespace std; class MyList{ public: struct node{ int value; node *next; node(int initValue):value(initValue), next(nullptr){} }; MyList(){ _dummyHead = new node(0); _size = 0; } // 获取第index个结点的数值 int get(int index){ if(index > (_size-1) || index < 0){ // throw out_of_range("index out of range!"); cout << "index out of range!————return INT32_MAX = " << INT32_MAX << endl; return INT32_MAX; } node *cur = _dummyHead->next; while(index){ cur = cur->next; index--; } return cur->value; } // 在链表最前面插入一个节点 void addAtHead(int value){ node *newNode = new node(value); newNode->next = _dummyHead->next; _dummyHead->next = newNode; _size++; } // 在链表最后面插入一个元素 void addAtTail(int value){ node *newNode = new node(value); node *cur = _dummyHead; while(cur->next != nullptr){ cur = cur->next; } cur->next = newNode; _size++; } // 在第index个节点之前插入一个节点 void addAtIndex(int index, int value){ if(index > _size){ return; } if(index < 0){ index = 0; } node *newNode = new node(value); node *cur = _dummyHead; while(index != 0){ cur = cur->next; index--; } newNode->next = cur->next; cur->next = newNode; _size++; } // 删除第index个节点 void deleteAtIndex(int index){ if(index < 0 || index >= _size){ return; } node *cur = _dummyHead; while(index != 0){ cur = cur->next; index--; } node *tmp = cur->next; cur->next = cur->next->next; delete tmp; tmp = nullptr; _size--; } // 打印链表 void printList(){ node *cur = _dummyHead; while(cur->next != nullptr){ cout << cur->next->value; cur = cur->next; if(cur->next){ cout << "->"; } } cout << endl; } private: int _size; node *_dummyHead; }; int main(){ MyList list; list.addAtIndex(0,0); list.addAtIndex(1,1); list.addAtIndex(2,2); list.addAtIndex(3,3); list.addAtIndex(4,3); list.addAtIndex(5,4); list.printList(); list.deleteAtIndex(3); list.printList(); cout << list.get(1) << endl; return 0; }
-
双向链表设计测试
#include<iostream> using namespace std; class MyDualList{ public: struct node{ int value; node *next; node *prev; node(int initValue):value(initValue), next(nullptr), prev(nullptr){} }; MyDualList(){ _dummyHead = new node(0); _dummyTail = new node(0); _size = 0; _dummyHead->next = _dummyTail; _dummyTail->prev = _dummyHead; } int get(int index){ if(index < 0 || index >= _size){ return -1; } node *cur = _dummyHead->next; while(index){ cur = cur->next; index--; } return cur->value; } void addAtHead(int value){ node *newNode = new node(value); newNode->next = _dummyHead->next; _dummyHead->next->prev = newNode; // 跟单链表一致,只是在指针换向时多考虑一个prev指针 _dummyHead->next = newNode; newNode->prev = _dummyHead; // _size++; } void addAtTail(int value){ node *newNode = new node(value); // 这里设计的双向链表,与单向链表相比,末尾节点会指向_dummyTail,基于此可以像单向链表一样写 // 不过从另一个角度来说,我们的尾插可以看作在_dummyTail之前插入一个节点 _dummyTail->prev->next = newNode; newNode->prev = _dummyTail->prev; newNode->next = _dummyTail; _dummyTail->prev = newNode; _size++; } void addAtIndex(int index, int value){ if(index < 0)index=0; if(index > _size)return; node *cur = _dummyHead; while(index){ cur = cur->next; index--; } node *newNode = new node(value); newNode->next = cur->next; cur->next->prev = newNode; cur->next = newNode; newNode->prev = cur; _size++; } void deleteAtIndex(int index){ if(index < 0 || index >= _size)return; node *cur = _dummyHead; while(index){ cur = cur->next; index--; } node *tmp = cur->next; cur->next = cur->next->next; cur->next->prev = cur; delete tmp; _size--; } void printListForward(){ node *cur = _dummyHead; while(cur->next != _dummyTail){ cout << cur->next->value; cur = cur->next; if(cur->next != _dummyTail){ cout << "->"; } } cout << endl; } void printListReverse(){ node *cur = _dummyTail; while(cur->prev != _dummyHead){ cout << cur->prev->value; cur = cur->prev; if(cur->prev != _dummyHead){ cout << "<-"; } } cout << endl; } private: int _size = 0; node *_dummyHead, *_dummyTail; }; int main(){ MyDualList list; list.addAtIndex(0,0); list.addAtIndex(1,1); list.addAtIndex(2,2); list.addAtIndex(3,3); list.addAtIndex(4,3); list.addAtIndex(5,4); list.addAtTail(60); list.printListForward(); list.printListReverse(); list.deleteAtIndex(3); list.printListForward(); list.printListReverse(); cout << list.get(1) << endl; return 0; }