什么是链表?
要想知道什么是链表,我们要知道什么是链式存储
什么是链式存储?
要想知道什么是链式存储,我们要知道什么是线性存储,什么是线性表
线性存储&线性表
通俗来说,将逻辑有序的内容实际(物理空间)也有序地存储在一起,就是线性存储,
那线性表,就是将一堆线性存储的数据,比如说我们编程经常使用的数组
type array_name[length];
线性表的存储修改等操作都是通过数学公式实现的,因此速度较快,但是必须在最开头确定长度(存储空间大小)
复杂度:
获取长度 O(1)
修改 O(1)
删除 O(n)
移动 O(n)
查找 O(1)
空间复杂度:T(n) ∈ O(n)
链式存储是将将逻辑有序的内容实际(物理空间)无序地存储在一起,
换句话说,链表存储的数据元素,其物理存储位置是随机的
数据元素随机存储,并通过指针表示数据之间逻辑关系的存储结构就是链式存储结构
比如说在一个抽屉里放了一些东西(数据),然后里面还有一张小纸条,告诉你,下面一个(些)数据放在哪里
struct Drawer{
int value;
Drawer* next;
};
当然,我们也可以在抽屉里不仅放一个数据,可以放一个收纳盒,标准的形式就是这样:
struct information {
int data;
// another information
};
struct node;
typedef node* n;
struct node {
information value;
n next;
};
我们也可以不仅只存储它的直接后继(next),再存储它的直接前驱(prev),那么就变成了一个双向链表
struct node {
information value;
n next, prev;
};
再设计它的存取函数
struct node {
information value;
n prev, next;
int getifm()
{
return this->value.data;
}
int setifm(int x)
{
this->value.data = x;
}
};
至此,我们已经设计好了一个链表节点里的所有内容
因此,链表的节点由两个部分组成
也就是数据域,和指针域,其中数据域存储数据,就是我们刚刚写的information value,而指针域存储前一个结点下一个节点等联系,也就是我们刚刚写的n prev, next。
由此你就可以和你朋友吹牛了
但是如果你想在深入了解,请往下看
链表实质就是顺序表的链式表示。相比于顺序表有一些不同。顺序表是用一片地址连续的空间进行存储的 因此具有随机存储的特征(时间复杂度为O(1)),但是链表不同,链表不需要一片地址连续的空间 而是通过链(指针)来将所有元素串起来的。顺序表具有随机存储 但是插入、删除原素需要移动大量元素 而链表就是为了改善增删而定的 但是同时也失去了具有随机存取的特征,并且还需要有一个指针域(存储空间就增大了)。当访问某个元素时 只有通过链依次查找 具体看图例。
单链表:
(单)链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域,一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向 null(空指针的意思)。链接的入口节点也就是 head(头结点)。
请看下图
也就是链式存储最基本的一种方式
双链表
双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。既可以向前查询也可以向后查询。
请看下图
当然链表和链式存储是不一样的,可以说链表是链式存储的一种,而链式存储是个概念
我将会从最基础入手到最后的实战详细的讲述
循环链表
链表首尾相连
请看下图
链表初始化:
struct LinkNode
{
void* data;
struct LinkNode* next;
}
struct LList
{
struct LinkNode pHeader;
int m_Size;
}
typedef void * LinkList;
LinkList init_LinkList()
{
struct LList * mylist = malloc(sizeof(struct LList));
if(mylist == NULL)
{
return;
}
mylist->pHeader.data = -1;
mylist->pHeader.next = NULL;
mylist->m_Size = 0;
return mylist;
}
这是一段一本质为基础的初始化但为了让你们看得懂给你们简化一下
struct list //创建链表
{
int price;
list* next;
};
list* head = new list;
list* cur = head;
list* tail = 0;
//初始化链表
for (int i = 0; i < n; i++) {
cur->price = 0;
cur->next = new list;
tail = cur;
cur = cur->next;
}
简化后采用了最基础的for来循环创建新的结构体来组成链表
其中cur一直在后移创建新的结构体,并用next串联起来完成初始化
链表基本操作:
void interpose/*插入*/(int x/*插入的数据*/, int m/*插入的位置*/,list* head1/*指向链表头节点的指针*/) {
list* uoer = head1;
for (int i = 0; i < m; i++) {uoer = uoer->next;}//移动指针到相应位置
list* temp = uoer->next;//保留下个结构体的指针
uoer->next = new list;//创建新的结构体list是链表名 new不是!!new不能丢!!
uoer->next->next = temp;//链接下个结构体
uoer->next->price = x;//写入数据
}
void Print_list/*打印链表*/(list* head1/*指向链表头节点的指针*/,int n/*链表节点数*/) {
list* uoer = head1;
for (int i = 0; i < n; i++) {//输出
cout << uoer->price<<" ";
cur = uoer->next;
}
}
void _delete/*删除*/(int x/*删除的数据*/, int m/*删除的位置*/,list* head1/*指向链表头节点的指针*/) {
list* uoer = head1;
for (int i = 0; i < m; i++) {uoer = uoer->next;}//移动指针到相应位置
uoer->next = uoer->next->next;//删除
}
void _delete/*覆盖*/(int x/*覆盖的数据*/, int m/*覆盖的位置*/,list* head1/*指向链表头节点的指针*/) {
list* uoer = head1;
for (int i = 0; i < m; i++) {uoer = uoer->next;}//移动指针到相应位置
uoer->next->price = x;//覆盖
}
string transform/*链表转字符串*/(list* head1/*指向链表头节点的指针*/,int n/*链表长度*/) {
list* uoer = head1;
string s1;
for (int i = 0; i < n; i++) {
s1[i] = uoer->price;
uoer = uoer->next;
}
return s1;
}
【023】C/C++数据结构之链表及其实战应用-CSDN博客
C++链表的应用实例_c++链表案例-CSDN博客