数据结构 || 单链表学习总结

前言
  • 在顺序表中,用一组地址连续的存储单元来存放线性表的结点,因此结点的逻辑顺序和物理顺序是一致的。
  • 链表使用一组任意的存储单元来存放线性表的结点
单链表
1.简介
  • 单链表结构图示
    在这里插入图片描述
1.1:单链表特点
  • 结点包括两个域:一个 数据域(用来存储结点的值) 和一个 指针域(用来指向该结点的直接后继结点的位置)
  • 相比于顺序表的优点:对于空间的利用率 大大提高,实现了即用既申请.
  • 相比于顺序表的缺点:在访问表中的某个结点(尾结点)时,需要遍历整个链表
2.单链表的实现
2.1:单链表结点结构的定义
typedef int SLDataType;

typedef struct SLNode{
  SLDataType _value;
  struct SLNode *next;
}SLNode;

2.2:指向链表的首结点的定义
typedef struct SList{
  SLNode *first;
}SList;

2.3:单链表头结点的初始化
//初始化
void SListInit(SList*list){
  assert(list!=NULL);
  list->first=NULL;
}

2.4:单链表的销毁
  • 算法思想
  • 1.定义一个指针指向(*cur)要销毁的结点,一个指针(*next)指向该节点的下一个结点
  • 2.用指针cur来遍历结点,并将遍历到的结点销毁
  • 3.用指针next来确保不会将单链表中其他结点丢失
  • 4.最后将指向该链表的指针置空
//需要遍历整个链表且将遍历到的结点释放掉
void SListDestory(SList *list){
  assert(list!=NULL);
  SLNode* cur=list->first;
  SLNode *next=NULL;
  while(cur!=NULL){
   next=cur->next;
   free(cur);
   cur=next;
  }
  list->first=NULL;
}

  • 动图演示
    在这里插入图片描述
2.5:单链表的头插
  • 算法思想
  • 1.申请一个新的结点,并将新结点的值置为指定的值
  • 2.让新结点的next指针指向链表原来的首结点
  • 3.让原来指针链表首结点的指针指向新结点
void SListPushFront(SList *list,SLDataType value){
  assert(list!=NULL);
  SLNode* new_node=(SLNode*)malloc(sizeof(SLNode));
  new_node->_value=value;
  new_node->next=list->first;
  list->first=new_node;
}
  • 动图演示
    在这里插入图片描述
2.6:单链表的尾插
  • 算法思想
  • 1.申请一个新的结点,并将结点的值置为指定的插入值
  • 2.遍历整个单链表,找到单链表的尾结点
  • 3.将新结点的next指针指向NULL
  • 4.原来尾节点的next指针指向新的结点
//尾插
void SListpushBack(SList *list, SLDataType value){
  assert(list!=NULL);
  //寻找尾部
  SLNode* cur=list->first;
  SLNode* new_node=(SLNode *)malloc(sizeof(SLNode));
  while(cur->next!=NULL){
    cur=cur->next;
  }
  new_node->_value=value;
  new_node->next=cur->next;
  cur->next=new_node;
}
  • 动图演示
    在这里插入图片描述
2.7:单链表结点的头删
  • 算法思想
  • 1.定义一个指向单链表首结点的指针
  • 2.将原来指向单链表首结点的指针指向它的下一个结点位置
  • 3.将原来的首结点释放
//头删
void SListPopFront(SList *list){
assert(list!=NULL);    //保证链表存在
assert(list->first!=NULL);  //保证链表不为空

SLNode *tmp=list->first;
list->first=list->first->next;
free(tmp); 
}
  • 动图演示
    在这里插入图片描述
2.8:单链表结点的尾删
  • 算法思想
  • 1.首先要确定该链表的是否只有一个结点,若是则调用头删函数即可
  • 2.若不是,就需要找到尾节点的前一个结点,再将尾节点释放
//尾删
void SListPopBack(SList *list){
  assert(list!=NULL);
  assert(list->first!=NULL);
  //如果只有一个结点需要特殊处理
  
  if(list->first->next==NULL){
    SListPopFront(list);
    return;
  }
  SLNode *cur=list->first;

  while(cur->next->next!=NULL){ 
    cur=cur->next;
  }

  free(cur->next);
  cur->next=NULL;
}
  • 动图演示
    在这里插入图片描述
2.9:单链表中指定结点的查找
  • 算法思想
  • 1.遍历整个链表查找结点值与给定值相等的结点
  • 2.若找到,则将找到的结点返回
  • 3.若没有找到,则返回NULL
//查
SLNode * SListFind(const SList *list, SLDataType value){
  assert(list!=NULL);
  assert(list->first!=NULL);
  SLNode *cur=list->first;
  while(cur!=NULL){
    if(cur->_value==value)
      return cur;
    cur=cur->next;
  }
  return NULL;
}
2.10:单链表结点值的打印
  • 算法思想
  • 1.遍历整个链表的时将各个结点的值输出
//打印
void SListPrint(SList *list){
  assert(list!=NULL);

 SLNode *cur=list->first;
  while(cur!=NULL){
    printf("%d-->",cur->_value);
    cur=cur->next;
  }
  printf("\n");
 }
2.11:修改指定结点的值
void  SlistNodeUpdate(SLNode *node, SLDataType value){
  node->_value=value;
}

2.12:在指定的位置插入新的结点
  • 算法思想
  • 1.申请新的结点,并将给定值赋给该结点
  • 2.对给定位置的结点进行"尾插"
//指定位置插入元素
//1-->2-->3-->NULL
//pos 一定是链表中的有效节点
void SListInsertAfter(SLNode *pos, SLDataType value){
  assert(pos!=NULL);
  SLNode *new_node=(SLNode*)malloc(sizeof(SLNode));
  new_node->_value=value;
  new_node->next=pos->next;
  pos->next=new_node;
}

2.13:删除指定位置下一个结点
  • 算法思想
  • 1.定义一个指针指向给定结点的下一个结点
  • 2.将给定结点的next指针指向该结点的下一个的下一个结点
  • 3.再将定义的指针指向的空间释放
//删除给定pos位置后面的结点
void SListEraseAfter(SLNode *pos){
  assert(pos!=NULL);
  SLNode* cur=pos->next;
  pos->next=pos->next->next;
  free(cur);
}
2.14:在指定位置前面插入新的结点
  • 算法思想
  • 1.在给定链表中查找给定结点的前一个结点
  • 2.申请新的结点并将给定值赋给新结点
  • 3.对给定结点的前一个结点进行"尾插"
//指定位置pos 前面插入新结点
void SListInsertBefore(SList *list, SLNode *pos, SLDataType value){
  assert(list!=NULL);
  assert(pos!=NULL);
  SLNode *new_node=(SLNode*)malloc(sizeof(SLNode));
  
  SLNode* cur=list->first;
  while(cur->next!=pos){
    cur=cur->next;
  }
 
  new_node->_value=value;
  new_node->next=pos;
  cur->next=new_node;
}
单链表功能的整体实现
SList.h
#pragma once
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>


typedef int SLDataType;

typedef struct SLNode{
  SLDataType _value;
  struct SLNode *next;
}SLNode;

typedef struct SList{
  SLNode *first;
}SList;


//初始化
void SListInit(SList*list);

//销毁过程
void SListDestory(SList *list);

//增
//头插
void SListPushFront(SList *list,SLDataType value);
//尾插
void SListpushBack(SList *list, SLDataType value);





//删
//头删
void SListPopFront(SList *list);
//尾删
void SListPopBack(SList *list);

//打印
void SListPrint(SList *list);

//查
SLNode * SListFind(const SList *list, SLDataType value);

//改
void  SlistNodeUpdate(SLNode *node, SLDataType value);

//指定位置插入元素
//1-->2-->3-->NULL

void SListInsertAfter(SLNode *pos, SLDataType value);

//删除给定pos位置后面的结点
void SListEraseAfter(SLNode *pos);

//指定位置pos 前面插入新结点
void SListInsertBefore(SList *list, SLNode *pos, SLDataType value);
SList.c
#include"SList.h"
//->指针解引用
//. 变量解引用

//初始化
void SListInit(SList*list){
  assert(list!=NULL);
  list->first=NULL;
}

//销毁过程(不太熟练)
//需要遍历整个链表且将遍历到的结点释放掉
void SListDestory(SList *list){
  assert(list!=NULL);
  SLNode* cur=list->first;
  SLNode *next=NULL;
  while(cur!=NULL){
   next=cur->next;
   free(cur);
   cur=next;
  }
  list->first=NULL;
}

//增
//头插
void SListPushFront(SList *list,SLDataType value){
  assert(list!=NULL);
  SLNode* new_node=(SLNode*)malloc(sizeof(SLNode));
  new_node->_value=value;
  new_node->next=list->first;
  list->first=new_node;
}


//尾插
void SListpushBack(SList *list, SLDataType value){
  assert(list!=NULL);
  //寻找尾部
  SLNode* cur=list->first;
  SLNode* new_node=(SLNode *)malloc(sizeof(SLNode));
  while(cur->next!=NULL){
    cur=cur->next;
  }
  new_node->_value=value;
  new_node->next=cur->next;
  cur->next=new_node;
}
//删
//头删

void SListPopFront(SList *list){
assert(list!=NULL);    //保证链表存在
assert(list->first!=NULL);  //保证链表不为空

SLNode *tmp=list->first;
list->first=list->first->next;
free(tmp); 
}

//尾删
void SListPopBack(SList *list){
  assert(list!=NULL);
  assert(list->first!=NULL);
  //如果只有一个结点需要特殊处理
  
  if(list->first->next==NULL){
    SListPopFront(list);
    return;
  }
  SLNode *cur=list->first;

  while(cur->next->next!=NULL){ 
    cur=cur->next;
  }

  free(cur->next);
  cur->next=NULL;
}

//打印
void SListPrint(SList *list){
  assert(list!=NULL);

 SLNode *cur=list->first;
  while(cur!=NULL){
    printf("%d-->",cur->_value);
    cur=cur->next;
  }
  printf("\n");
 }

//查
SLNode * SListFind(const SList *list, SLDataType value){
  assert(list!=NULL);
  assert(list->first!=NULL);
  SLNode *cur=list->first;
  while(cur!=NULL){
    if(cur->_value==value)
      return cur;
    cur=cur->next;
  }
  return NULL;
}

//改
void  SlistNodeUpdate(SLNode *node, SLDataType value){
  node->_value=value;
}

//指定位置插入元素
//1-->2-->3-->NULL
//pos 一定是链表中的有效节点
void SListInsertAfter(SLNode *pos, SLDataType value){
  assert(pos!=NULL);
  SLNode *new_node=(SLNode*)malloc(sizeof(SLNode));
  new_node->_value=value;
  new_node->next=pos->next;
  pos->next=new_node;
}

//删除给定pos位置后面的结点
void SListEraseAfter(SLNode *pos){
  assert(pos!=NULL);
  SLNode* cur=pos->next;
  pos->next=pos->next->next;
  free(cur);
}

//指定位置pos 前面插入新结点
void SListInsertBefore(SList *list, SLNode *pos, SLDataType value){
  assert(list!=NULL);
  assert(pos!=NULL);
  SLNode *new_node=(SLNode*)malloc(sizeof(SLNode));
  
  SLNode* cur=list->first;
  while(cur->next!=pos){
    cur=cur->next;
  }
 
  new_node->_value=value;
  new_node->next=pos;
  cur->next=new_node;
}

main.c
#include"SList.h"



void TestSLNode(){
  SList slist;
  SListInit(&slist);
  SListPushFront(&slist,1);
  SListPushFront(&slist,9);
  //9  1
  SListPrint(&slist);
  SListPushFront(&slist,8);
  SListPrint(&slist);
  // 8 9 1
  SListPushFront(&slist,5);
  SListPrint(&slist);
  // 5 8 9 1
  SListpushBack(&slist,4);
  SListpushBack(&slist,3);
  SListpushBack(&slist,2);
  SListpushBack(&slist,100);
  SListPrint(&slist);
  //5 8 9 1 4 3 2 100
  SListPopFront(&slist);
  // 8 9 1 4 3 2 100
  SListPopBack(&slist);
  SListPrint(&slist);
  // 8  9 1 4 3 2 
  SListPopFront(&slist);
  //9  1 4 3 2 
  SListPrint(&slist);
  SLNode* node=SListFind(&slist,3);
  SListEraseAfter(node);
  // 9  1 4 3 
  SListInsertAfter(node,520);
  // 9 1 4 3 520
  SListPrint(&slist);
  SListEraseAfter(node);
  // 9 1 4 3 
  SListInsertBefore(&slist,node,1314);
  // 9 1 4   1314 3 
  SListPrint(&slist);
}

int  main()
{
  TestSLNode();
  return 0;
}
  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值