1、构造一个空的单链表L
即创建一个头结点,时间复杂度O(1)、空间复杂度O(1)
2、头插法初始化链表,时间复杂度O(1)、空间复杂度O(n){根据元素个数而言}
3、尾插法初始化链表,时间复杂度O(1)、空间复杂度O(n){根据元素个数而言}
4、获取单链表第i个元素,时间复杂度O(n) {与i有关}、空间复杂度O(1)
5、在带头结点的单链表L中查找值为e的元素,时间复杂度(n)、空间复杂度O(1)
6、在第i个位置插入新的链表节点,时间复杂度O(n)、空间复杂度O(1)
7、单链表的第i个节点的删除,时间复杂度O(n)、空间复杂度O(1)
8、打印链表,时间复杂度O(n)、空间复杂度O(1)
/**
* @file main.cpp
* @author your name (you@domain.com)
* @brief 单向链表
* @version 0.1
* @date 2022-04-26
*
* @copyright Copyright (c) 2022
*
*/
#include <iostream>
using namespace std;
//定义链表节点结构体
typedef struct Lnode
{
int data; //存储数据
struct Lnode *next; //存储下一个节点的内存地址
} LNode, *LinkList; //使用typedef定义别名,LNode等价于Lnode,LinkList等价于Lnode*
/**
* @brief 构造一个空的单链表L 即创建一个头结点,时间复杂度O(1)、空间复杂度O(1)
*
* @param L 链表节点结构体指针引用
* @return true 头结点生成成功
* @return false 头结点生成失败
*/
bool InitList_L(LinkList &L)
{
= new LNode; //生成新结点作为头结点,用头指针L指向头结点
L if (!L)
return false; //生成结点失败
->next = NULL; //头结点的指针域置空
Lreturn true;
}
/**
* @brief 头插法初始化链表,时间复杂度O(1)因为n是来我们确定的他是个常数、空间复杂度O(n)[根据元素个数而言]
*
* @param L 存储头结点地址的指针的引用
*/
void CreateList_H(LinkList &L)
{
int n; //输入n个元素的值,建立到头结点的单链表L
; //定义一个指针变量
LinkList s= new LNode; //创建头结点
L ->next = NULL; //先建立一个带头结点的空链表
L<< "请输入元素个数n:" << endl;
cout >> n;
cin << "请依次输入n个元素:" << endl;
cout << "前插法创建单链表..." << endl;
cout while (n--)
{
= new LNode; //生成新结点s
s >> s->data; //输入元素值赋给新结点的数据域
cin ->next = L->next;
s->next = s; //将新结点s插入到头结点之后
L}
}
/**
* @brief 尾插法初始化链表,时间复杂度O(1)、空间复杂度O(n)[根据元素个数而言]
*
* @param L 存储单链表头结点地址指针的引用
*/
void CreateList_R(LinkList &L)
{
//输入n个元素的值,建立带表头结点的单链表L
int n;
, r;
LinkList s= new LNode; //创建头结点
L ->next = NULL; //先建立一个带头结点的空链表
L= L; //尾指针r指向头结点
r << "请输入元素个数n:" << endl;
cout >> n;
cin << "请依次输入n个元素:" << endl;
cout << "尾插法创建单链表..." << endl;
cout while (n--)
{
= new LNode; //生成新结点
s >> s->data; //输入元素值赋给新结点的数据域
cin ->next = NULL;
s->next = s; //将新结点s插入尾结点r之后
r= s; // r指向新的尾结点s
r }
}
时间复杂度、获取第1个元素需要1次循环,第2个2个循环,则平均复杂度为 (1+2+3+…+n)/n=(n+1)/2,即O(n)
/**
* @brief 获取单链表第i个元素,时间复杂度O(n)[与i有关]、空间复杂度O(1)
*
* @param L 存储单链表头结点地址指针的引用
* @param i 获取第i个节点的数据
* @param e 将第i个节点数据赋值给int&e,以便在函数外可以得到数据
* @return true 获取第i个数据成功
* @return false 获取第i个数据失败
*/
bool GetElem_L(LinkList L, int i, int &e)
{
//在带头结点的单链表L中查找第i个元素
//用e记录L中第i个数据元素的值
int j;
;
LinkList p= L->next; // p指向第一个数据结点
p = 1; // j为计数器
j //寻找指定节点
while (j < i && p) //顺着链表向后扫描,直到p指向第i个元素或p为空
{
= p->next; // p指向下一个结点
p ++; //计数器j相应加1
j}
if (!p || j > i)
return false; // i值不合法i>n或i<=0
//取值
= p->data; //取第i个结点的数据域
e return true;
}
复杂度分析类似于,获取第i个元素复杂度分析
/**
* @brief 在带头结点的单链表L中查找值为e的元素,时间复杂度(n)、空间复杂度O(1)
*
* @param L 存储单链表头结点地址指针的引用
* @param e 需要查找的值(节点data域)
* @return size_t 目标元素所在第几个位置,头结点为第0个,如果没找到指定元素则返回0
*/
size_t LocateElem_L(LinkList L, int e)
{
;
LinkList p= L->next; //指向第1个数据节点
p std::size_t index = 1;
while (p && p->data != e) //沿着链表向后扫描,直到p空或p所指结点数据域等于e
{
= p->next; // p指向下一个结点
p ++;
index}
if (!p)
return 0; //查找失败p为NULL
return index;
}
复杂度类似于获取第i个元素类似,我们在第i个位置插入总需要至少i-1比较
/**
* @brief 在第i个位置插入新的链表节点,时间复杂度O(n)、空间复杂度O(1)
*
* @param L 存储单链表头结点地址指针的引用
* @param i 插入到第i位置
* @param e 新节点的data域要存储的内容
* @return true 插入新节点成功
* @return false 插入新节点失败
*/
bool ListInsert_L(LinkList &L, int i, int e)
{
//在带头结点的单链表L中第i个位置插入值为e的新结点
int j;
, s; // p为迭代器指针,s指针用于存储生成新的节点的内存地址
LinkList p= L; //将迭代器指针存储为链表的头结点地址
p = 0; // j记录p现在在第几个节点,头结点在第0个位置
j while (p && j < i - 1) //查找第i-1个结点,p指向该结点,可见i应该大于等于1,要找的目标节点为j==i-1,即第i个节点的前一个节点
{
= p->next;
p ++;
j}
if (!p || j != i - 1) //表链表没有第i个节点(头结点为第0个节点),我们要的效果是j==i-1
return false; //插入失败
//找到了第i个位置的前一个节点
= new LNode; //生成新结点
s ->data = e; //将新结点的数据域置为e
s->next = p->next; //将新结点的指针域指向结点ai
s->next = s; //将结点p的指针域指向结点s
preturn true; //插入成功
}
复杂度分析与获取第i个元素类似
/**
* @brief 单链表的第i个节点的删除,时间复杂度O(n)、空间复杂度O(1)
*
* @param L 存储单链表头结点地址指针的引用
* @param i 删除第i个节点,头结点为第0个节点
* @return true 删除成功
* @return false 删除失败
*/
bool ListDelete_L(LinkList &L, int i)
{
//在带头结点的单链表L中,删除第i个位置
, q;
LinkList pint j;
= L;
p = 0;
j //先找第i-1个位置的节点,即寻找第i个位置的前一个位置的节点
while ((p->next) && (j < i - 1)) //查找第i-1个结点,p指向该结点
{
= p->next;
p ++;
j}
if (!(p->next) || j != i - 1) //链表没有第i节点或、当i>n或i<1时,删除位置不合理
return false;
= p->next; //临时保存被删结点的地址以备释放空间
q ->next = q->next; //改变删除结点前驱结点的指针域
pdelete q; //释放被删除结点的空间
return true;
}
/**
* @brief 打印链表,时间复杂度O(n)、空间复杂度O(1)
*
* @param L 存储单链表头结点地址指针的引用
*/
void printLinklist(LinkList &L)
{
if (L == nullptr)
{
return;
}
*p = L->next;
LNode while (p)
{
std::cout << p->data << " " << std::endl;
= p->next;
p }
}
/**
* @brief 单链表数据结构测试
*
* @param argc
* @param argv
* @return int
*/
int main(int argc, char **argv)
{
;
LinkList mlist//以头插法初始化为例子
(mlist); // input 1 2 3 4 5 6 7 8 9 10
CreateList_H(mlist); // output 10 9 8 7 6 5 4 3 2 1
printLinklistint e;
(mlist, 2, e);
GetElem_L<< e << endl; // 9
cout << LocateElem_L(mlist, 9) << endl; // 2
cout (mlist, 1, 888);
ListInsert_L(mlist); // 888 10 9 8 7 6 5 4 3 2 2 1
printLinklist(mlist, 2);
ListDelete_L(mlist); // 888 9 8 7 6 5 4 3 2 1
printLinklistreturn 0;
}