【C语言】链表及单链表基本操作

1、什么是链表?链表的分类?

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

数据结构中:

在这里插入图片描述

2、链表的分类

共有8种链表结构
在这里插入图片描述

3、单链表的基本操作

类似于顺序表,我们来实现单链表的基本操作,具体见SList.h 代码中语句及注释。

#pragma once
typedef int SDataType;
//链表的节点
typedef struct SListNode
{
 SDataType _data;
 struct SListNode* _PNext;
}Node,*PNode;

typedef struct SList       //封装了链表的结构
{
 PNode _pHead;//指向链表第一个节点
}SList;

void SListInit(SList*s);//链表的初始化

//在链表s最后一个节点后插入一个值为data的节点
void SListPushBack(SList* s, SDataType data);

//删除链表s最后一个节点
void SListPopBack(SList* s);

//在链表s第一个节点前插入值为data的节点
void SListPushFront(SList* s, SDataType data);

//删除链表s的第一个节点
void SListPopFront(SList* s);

//在链表的pos位置后插入值为data的节点
void SListInsert(PNode pos, SDataType data);

//删除链表s中pos位置的节点
void SListErase(SList* s, PNode pos);

// 在链表中查找值为data的节点,找到返回该节点的地址,否则返回NULL 
PNode SListFind(SList* s, SDataType data);

//移除链表中第一个值为data的元素
void SListRemove(SList*s, SDataType data);

// 获取链表中有效节点的个数 
int SListSize(SList* s);

// 检测链表是否为空 
int SListEmpty(SList* s);

// 将链表中有效节点清空 
void SListClear(SList* s);

// 销毁链表 
void SListDestroy(SList* s);
//打印链表
void SListPrint(SList* s);

以下为SList.c具体代码:

#include <stdio.h>
#include "Slist.h"
#include <assert.h>
#include <stdlib.h>
#include <stddef.h>

1.初始化部分,我们只需要将链表的头结点置为NULL即可。

void SListInit(SList*s) {
 assert(s);
 s->_pHead = NULL;
}

2.尾插,首先我们要创建一个新节点,然后判断链表当前是否有节点,若没有,则直接让第一个节点指向新节点,若有,找到最后一个节点,让他指向新节点。

void SListPushBack(SList* s, SDataType data) {
 //找链表最后一个节点
 assert(s);
 PNode pNewNode = BuySListNode(data);
 if (s->_pHead == NULL) {//链表没有节点的情况
  s->_pHead = pNewNode;
 }
 else {
  PNode pCur = s->_pHead;
  while (pCur->_PNext) {
   pCur = pCur->_PNext;
  }
  //让最后一个节点指向新节点
  pCur->_PNext = pNewNode;
 }
}

3.尾删,首先判断链表中有没有节点,若没有,直接返回,若有一个节点,直接让第一个节点指向NULL,若有多个节点,则需要记录下倒数第二个节点,让它指向NULL。

void SListPopBack(SList* s) {
 assert(s);
 if (s->_pHead == NULL) {//链表中没有节点
  return;
 }
 else if (s->_pHead->_PNext == NULL) {//只有一个节点
  free(s->_pHead);
  s->_pHead = NULL;
 }
 else {                           //多个节点
  PNode pCur = s->_pHead;
  PNode pPre = NULL;
  while (pCur->_PNext) {
   pPre = pCur;
   pCur = pCur->_PNext;
  }
  free(pCur);
  pPre->_PNext = NULL;
 }
}

4.头插

void SListPushFront(SList* s, SDataType data) {
 assert(s);
 PNode pNewNode = BuySListNode(data);
 if (s->_pHead == NULL) {//链表为空
  s->_pHead = pNewNode;
 }
 else {
  pNewNode->_PNext = s->_pHead;
  s->_pHead = pNewNode;
 }
}

5.头删

void SListPopFront(SList* s) {
 assert(s);
 if (s->_pHead == NULL) {//链表为空
  return;
 }
 else if (s->_pHead->_PNext == NULL) {//只有一个节点
  free(s->_pHead);
  s->_pHead = NULL;
 }
 else {
  PNode pCur = s->_pHead;
  s->_pHead = pCur->_PNext;
  free(pCur);
 }
}

6.在给定pos位置插入值为data的节点,分两步完成:首先找到pos位置的节点,然后再插入,所以要实现这一个功能需要两个函数来共同完成。

在这里插入图片描述
注意:应该先连接好新节点,再断开原来的指针指向。
插入:

void SListInsert(PNode pos, SDataType data) {
 PNode pNewNode = NULL;
 if (pos == NULL) {
  return;
 }
 pNewNode = BuySListNode(data);
 
 pNewNode->_PNext = pos->_PNext;
 pos->_PNext = pNewNode;
}

查找:

PNode SListFind(SList* s, SDataType data) {
 assert(s);
 PNode pCur = s->_pHead;
 while (pCur) {
  if (pCur->_data == data) {
   return pCur;
  }
  pCur = pCur->_PNext;
 }
 return NULL;
}

7.删除给定pos位置的节点。
在这里插入图片描述

void SListErase(SList* s, PNode pos) {
 assert(s);
 if (pos == NULL || s->_pHead == NULL) {
  return;
 }
 if (pos== s->_pHead) {
  s->_pHead = pos->_PNext;
 }
 else {
  PNode pPrePos = s->_pHead;
  while (pPrePos&&pPrePos->_PNext != pos) {
   pPrePos = pPrePos->_PNext;
  }
  pPrePos->_PNext = pos->_PNext;
 }
 free(pos);
}

8.删除第一个值为data的节点。要分三种情况:链表为空直接返回、要删除的节点为第一个节点、其它位置的节点。

void SListRemove(SList*s, SDataType data) {
 assert(s);
 if (s->_pHead == NULL) {
  return;
 }
 PNode pPre = NULL;
 PNode pCur = s->_pHead;
 while (pCur) {
  if (pCur->_data == data) {
   if (pCur == s->_pHead) {         //要删除的是第一个位置的节点
    s->_pHead = pCur->_PNext;
   }
   else {
    pPre->_PNext = pCur->_PNext;      //其它位置的情况,让前一个节点指向其后一个节点
   }
   free(pCur);
   return;
  }
  else {
   pPre = pCur;
   pCur = pCur->_PNext;
  }
 }
}

其它:

int SListSize(SList* s) {            //获取链表有效节点的个数
 assert(s);
 int count = 0;
 PNode pCur = s->_pHead;
 while (pCur) {
  count++;
  pCur = pCur->_PNext;
 }
 return count;
}

int SListEmpty(SList* s) {              //检测链表是否为空
 assert(s);
 if (s->_pHead == NULL) {
  return -1;
 }
 return 0;
}

void SListClear(SList* s) {             //清空链表
 assert(s);
 if (s->_pHead == NULL) {
  return;
 }
 PNode pCur = s->_pHead;
 while (pCur->_PNext) {    //循环清空链表中的节点
  PNode Tmp = pCur->_PNext;
  free(pCur);
  pCur = Tmp;
 }
 if (pCur) {      //清空最后一个节点
  free(pCur);
  pCur = NULL;
 }
}

void SListDestroy(SList* s) {            //销毁链表
 assert(s);
 if (s->_pHead == NULL) {
  free(s->_pHead);
  return;
 }
 while (s->_pHead) {    
  PNode Tmp = s->_pHead->_PNext;
  free(s->_pHead);
  s->_pHead = Tmp;
 }
}

void SListPrint(SList* s) {             //打印链表
 assert(s);
 PNode pCur = s->_pHead;
 while (pCur) {
  printf("%d--->", pCur->_data);
  pCur = pCur->_PNext;
 }
 printf("\n");
}
void main() {
 SList s;
 SListInit(&s);
 SListPushBack(&s, 1);
 SListPushBack(&s, 2);
 SListPushBack(&s, 3);
 printf("size=%d\n", SListSize(&s));
 SListPrint(&s);
 SListInsert(SListFind(&s, 2), 0);
 SListPrint(&s);
 SListRemove(&s, 2);
 SListPrint(&s);
  system("pause");
 return;
}

运行结果:
在这里插入图片描述

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页