数据结构——顺序表和链表(下)

简介: 笔记

尾部插入


1.png2.png


先建立一个新的节点


分为俩种情况,第一种头节点指向空,第二种头节点指向不为空


第一种情况:头节点为空,建立新的节点后,直接让头节点指向新节点

3.png

第二种情况,头节点不为空,创建一个跟节点类型相同的结构体变量,然后让这个变量指向头节点,之后检查后面的每个节点,若有一个节点为的next为空,则在此处插入新节点

4.png



tail发现这个节点的next指向为空,然后让这个节点的next指向下一个节点的地址,随着程序的结束tail也会随之消失

5.png


void SListpushback(SLTNode** pphead, SLTDataType x)
{
  //pphead不可能为空,pphead是plist的地址,pphead永远不为空
  //1.链表为空
  SLTNode* newnode = BuySLTnode(x);
  if (*pphead == NULL)
  {
  *pphead = newnode;
  }
  //2.不为空
  else
  {
  SLTNode* tail = *pphead;
  while (tail->next != NULL)
  {
    tail =tail->next;
  }
  tail->next = newnode;
  }
}


频繁的malloc会使效率降低

头部节点删除


6.png7.png8.png9.png

void SListpopfront(SLTNode** pphead)//头删
{
  SLTNode* del = *pphead;
  *pphead = (*pphead)->next;
  free(del);//删除第一个节点 
  del = NULL;
}

当全部删完后,plist指向NULL,此时就不能再删了。程序会崩溃,此时plsit为空,(*pphead)->next也为空,del也为空,因此加一个检查条件


void SListpopfront(SLTNode** pphead)//头删
{
if(*pphead==NULL)
{
return;
}
  SLTNode* del = *pphead;
  *pphead = (*pphead)->next;
  free(del);//删除第一个节点 
  del = NULL;
}


void SListpopfront(SLTNode** pphead)//头删
{
    assert(*pphead!=NULL);
  SLTNode* del = *pphead;
  *pphead = (*pphead)->next;
  free(del);//删除第一个节点 
  del = NULL;
}

尾部节点删除


要判断尾部有一个节点还是多个节点甚至没有节点

10.png

当tail->next为空,删除该节点,然后让前一个节点指向NULL


11.png

void SListpopback(SLTNode** pphead)
{
if(*pphead==NULL)
return;
if((*pphead)->next==NULL)
{
free(*pphead);
*pphead=NULL;
}
else
{
  SLTNode* prev = NULL;
  SLTNode* tail = *pphead;
  while (tail->next!= NULL)
  {
  prev = tail;
  tail = tail->next;
  }
  prev->next = NULL;
  free(tail);
  tail = NULL;
}
}


12.png

void SListpopback(SLTNode** pphead)
{
if(*pphead==NULL)
return;
if((*pphead)->next==NULL)
{
free(*pphead);
*pphead=NULL;
}
else
{
  SLTNode* tail = *pphead;
  while (tail->next->next!= NULL)
  {
  tail = tail->next;
  }
  free(tail->next);
  tail->next = NULL;
}
}


节点的销毁


13.png14.png

释放掉cur,cur=next ,不断往下走,最后把头节点置空


void SListDestory(SLTNode** pphead)//用二级指针会更好
{
  SLTNode* cur = *pphead;
  while (cur)
  {
  SLTNode* next = cur->next;
  free(cur);
  cur = next;
  }
  *pphead = NULL;
}

链表查找


SLTNode *SListFind(SLTNode** pphead, SLTDataType x)
{
  SLTNode* cur = *pphead;
  while (cur != NULL)
  {
  if (cur->data == x)
  {
    return cur;
  }
  cur = cur->next;
  }
  return NULL;
}

挨个查找。


随即插入


void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
  assert(pos);
  if (pos == *pphead)
  {
  SListpushfront(pphead, x);
  }
  else
  {
  SLTNode* prve = *pphead;
  while (prve->next != pos)
  {
    prve = prve->next;
    assert(prve);//找不到
  }
  SLTNode* newnode = BuySLTnode(x);
  prve->next = newnode;
  newnode->next = pos;
  }
}


从一个数的前面插入,若果头插则用头插函数


后插


void SListInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
  SLTNode* newnode = BuySLTnode(x);
  newnode->next = pos->next;
  pos->next = newnode;
}

删除某节点前面的节点


void SlistErase(SLTNode** pphead, SLTNode* pos)
{
  assert(pos);
  if (*pphead == pos)
  {
  SListpopfront(pphead);
  }//如果是头删,用头删函数
  else
  {
  SLTNode* prev = *pphead;
  if (prev->next != pos)
  {
    prev = prev->next;
    assert(prev);//判断pos是否属于本链表
  }
  prev->next = pos->next;
  free(pos);
  pos = NULL;
  }
}


删除某节点后面的节点


void SlistEraseAfter(SLTNode** pphead, SLTNode* pos)
{
  assert(pos);
  if (pos->next == NULL)
  return;
  else
  {
  SLTNode* prev = *pphead;
  prev = pos->next;
  pos->next = prev->next;
  free(prev);
  prev = NULL;
  }
}

单链表缺陷


单链表只适合头插头删,O(1)。


替换法删除节点



删除某个节点,要求是O(1)


15.png


把2所在节点删除,可采用以下方法, 我们把2,3进行交换

16.png

17.png

然后让3指向4


缺陷:所删节点不能是尾节点,尾节点后面是空的,无法交换


思路延申


在pos之前插入,要求是O(1)

19.png 我们不在之前插入,在之后进行插入

20.png21.png

然后交换值  

22.png

相关文章
|
8天前
|
Java
java数据结构,双向链表的实现
文章介绍了双向链表的实现,包括数据结构定义、插入和删除操作的代码实现,以及双向链表的其他操作方法,并提供了完整的Java代码实现。
java数据结构,双向链表的实现
|
1月前
|
存储 Java 索引
【数据结构】链表从实现到应用,保姆级攻略
本文详细介绍了链表这一重要数据结构。链表与数组不同,其元素在内存中非连续分布,通过指针连接。Java中链表常用于需动态添加或删除元素的场景。文章首先解释了单向链表的基本概念,包括节点定义及各种操作如插入、删除等的实现方法。随后介绍了双向链表,说明了其拥有前后两个指针的特点,并展示了相关操作的代码实现。最后,对比了ArrayList与LinkedList的不同之处,包括它们底层实现、时间复杂度以及适用场景等方面。
44 10
【数据结构】链表从实现到应用,保姆级攻略
|
18天前
|
存储 Java 程序员
【数据结构】初识集合&深入剖析顺序表(Arraylist)
Java集合框架主要由接口、实现类及迭代器组成,包括Collection和Map两大类。Collection涵盖List(有序、可重复)、Set(无序、不可重复),Map则由键值对构成。集合通过接口定义基本操作,具体实现由各类如ArrayList、HashSet等提供。迭代器允许遍历集合而不暴露其实现细节。List系列集合元素有序且可重复,Set系列元素无序且不可重复。集合遍历可通过迭代器、增强for循环、普通for循环及Lambda表达式实现,各有适用场景。其中ArrayList实现了动态数组功能,可根据需求自动调整大小。
29 11
|
26天前
|
存储 C语言 C++
数据结构基础详解(C语言) 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现
本文介绍了顺序表的定义及其在C/C++中的实现方法。顺序表通过连续存储空间实现线性表,使逻辑上相邻的元素在物理位置上也相邻。文章详细描述了静态分配与动态分配两种方式下的顺序表定义、初始化、插入、删除、查找等基本操作,并提供了具体代码示例。静态分配方式下顺序表的长度固定,而动态分配则可根据需求调整大小。此外,还总结了顺序表的优点,如随机访问效率高、存储密度大,以及缺点,如扩展不便和插入删除操作成本高等特点。
|
26天前
|
存储 算法 C语言
C语言手撕数据结构代码_顺序表_静态存储_动态存储
本文介绍了基于静态和动态存储的顺序表操作实现,涵盖创建、删除、插入、合并、求交集与差集、逆置及循环移动等常见操作。通过详细的C语言代码示例,展示了如何高效地处理顺序表数据结构的各种问题。
|
2月前
|
存储 Java 程序员
"揭秘HashMap底层实现:从数组到链表,再到红黑树,掌握高效数据结构的秘密武器!"
【8月更文挑战第21天】HashMap是Java中重要的数据结构,采用数组+链表/红黑树实现,确保高效查询与更新。构造方法初始化数组,默认容量16,负载因子0.75触发扩容。`put`操作通过计算`hashCode`定位元素,利用链表或红黑树处理冲突。`get`和`remove`操作类似地定位并返回或移除元素。JDK 1.8优化了链表转红黑树机制,提升性能。理解这些原理能帮助我们更高效地应用HashMap。
35 0
|
2月前
|
存储 算法
【初阶数据结构篇】顺序表和链表算法题
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
|
2月前
|
存储 测试技术
【初阶数据结构篇】双向链表的实现(赋源码)
因为头结点的存在,plist指针始终指向头结点,不会改变。
|
2月前
|
存储 测试技术
【初阶数据结构篇】单链表的实现(附源码)
在尾插/尾删中,都需要依据链表是否为空/链表是否多于一个节点来分情况讨论,目的是避免对空指针进行解引用造成的错误。
|
2月前
|
存储 测试技术
【初阶数据结构篇】顺序表的实现(赋源码)
线性表(linearlist)是n个具有相同特性的数据元素的有限序列。