链表
什么是链表
- 和数组一样,链表也是一种线性表
- .从内存结构来看,链表的内存结构是不连续的内存空间,是将一组零散的内存块串联起来,从而进行数据存储的数据结构。
- 链表中的每一个内存块被称为节点Node。
特点
- 插入、删除数据效率高O(1)级别(只需更改指针指向即可),随机访问效率低O(n)级别(需要从链头至链尾进行遍历)。
- 和数组相比,内存空间消耗更大,因为每个存储数据的节点都需要额外的空间存储后继指针。
单链表
- 每个节点只包含一个指针,即后继指针。
- 单链表有两个特殊的节点,即首节点和尾节点。为什么特殊?用首节点地址表示整条链表,尾节点的后继指针指向空地址null。
- 性能特点:插入和删除节点的时间复杂度为O(1),查找的时间复杂度为O(n)。
链表的操作
1、返回链表的长度
区别链表和数组
我们将数组比作货车,我们运输时要考虑的是货物的重量,不可以超过载重,而链表相当于是火车,不够就再加车厢,不用考虑载重的问题。即空间大小。
1、计算返回链表的长度(看有几个节点)
//首先定义节点
class Node:
def _init_(self,data=None):
self.data=data
self.next=None;
//实现单链表类
class LinkedList:
count=0
current=self.head
while current!=None//循环结束的条件
current +=1:
current=current.next
return count;
//时间复杂度为O(n),遍历整个链表
2、打印链表的全部内容(完整代码)
#include <iostream>
#usingnamespace std;
class ListNode { //首先创建一个ListNode的类表示链表中的节点
public:
int value;//value表示节点的值
ListNode* next;//next表示指向下一个节点的指针
ListNode(int value) : value(value), next(nullptr) {}
};
class LinkedList {
public:
ListNode* head;
LinkedList() : head(nullptr) {}//构造函数,用于初始化链表的头节点为nullptr。
void addNode(int value) {//用于表中添加节点
ListNode* newNode = new ListNode(value);//创建一个新的ListNode类型的节点,并将其值设置为value
if (head == nullptr) {//使用条件语句判断head指针是否为空。如果为空,将新节点设置为头结点。
head = newNode;
} else {
ListNode* cur = head;
while (cur->next != nullptr) {
cur = cur->next;
}//用于找到链表的尾节点。首先将cur指针指向头结点,然后遍历链表,直到找到最后一个节点,即cur->next为空
cur->next = newNode;
}
}
void disPlay() {//用于打印每个节点的值
ListNode* cur = head;
while (cur != nullptr) {
cout << cur->value << " ";
cur = cur->next;
}
cout << endl;
}
};
int main() {
LinkedList list;
list.addNode(56);
list.addNode(2);
list.addNode(223);
list.disPlay(); // 输出:56 2 223
return 0;
}
时间复杂度为O(n)
shijianfuza
3、指定位置插入元素(在链表第三个元素后面插入一个元素)
(在第i-1个节点后插入一个新节点)
- 先构造一个新节点,用S指向;
- 再找到链表的第i-1个节点,用P指向;
- 然后修改指针,插入节点(P之后插入新节点是S)
s->Next = p->Next; //把p的Next赋值给S的Next
p->Next = s; // 把S的值赋给P的Next
顺序不能错!!!如果对调会丢失p->Next的值
注意是否是插入到第一个元素,以及这个元素是否存在。
#include <iostream>
// 定义链表节点结构体
struct ListNode {
int val; // 节点的值
ListNode* next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(nullptr) {} // 构造函数,初始化节点的值和指针
};
// 在给定位置插入新节点
void insertNode(ListNode* head, int position, int value) {
ListNode* newNode = new ListNode(value); // 创建新节点
ListNode* current = head; // 当前节点指针
// 遍历链表,找到指定位置的节点
for (int i = 1; i < position && current != nullptr; i++) {
current = current->next;
}
// 如果指定位置超出链表长度,则输出错误信息并返回
if (current == nullptr) {
std::cout << "Position is out of range." << std::endl;
return;
}
// 注意点:插入新节点
newNode->next = current->next;
current->next = newNode;
}
// 打印链表内容
void printLinkedList(ListNode* head) {
ListNode* current = head; // 当前节点指针
// 遍历链表,打印节点的值
while (current != nullptr) {
std::cout << current->val << " ";
current = current->next;
}
std::cout << std::endl;
}
int main() {
// 创建链表示例
ListNode* head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
// 在第三个元素后插入新元素
insertNode(head, 3, 4);
// 打印链表内容
printLinkedList(head);
return 0;
}
//整体时间复杂度为O(n)
4、删除元素(删除第i个位置处的节点)
- 先找到链表的第(i-1)个节点,用P指向;
- 再用指针S指向要被删除的节点(p的下一个节点);
- 然后修改指针,删除S所指节点;
- 最后,释放S所指节点空间
P在前,S为要释放的空间。
s=p->Next;
p->Next=s->Next;
free(s);
5、查找某个元素是否存在
按照序号查找
List FindKth(int K,List Ptrl)
{
List p=PtrL;//p设为链表的头
int i=1;
while(p!=NULL&&i<k)//当p为空或者i等于k的时候,循环停止
{
p=p->Next;
i++;
}
if(i==k) return p;//找到了,第k个
else return NULL;//到最后也没找到,返回空,即不存在这个数
}//时间复杂度为n,需要遍历整个列表
按值查找
List Find(ElementType X,List PtrL)
{
List P=PtrL;
while (p!=NULL&&P->Data!=X)
P=P->Next;
return P;
}