单链表的基本操作以及单链表和顺序表的区别(C语言)

1.认识链表

链表的概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。
链表的结构:
在这里插入图片描述

2.链表的实现

链表的实现:
首先定义一个结构体,里面包含数据和一个指针。

typedef int SLTDataType;

typedef struct  SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLNode;

typedef重定义
例如:typedef (西红柿) (番茄);
我们就可以将西红柿叫做番茄。(即名字不同,但代表同一种事物)
typedef的好处:1.可以将很长的名字定义短些;
2.如上,我们将int定义成SLTDataType,也就是结构体里面的数据类型,如果想将单链表中的数据改为字符型,只需修改为(typedef char SLTDateType;),再修改个SListPrint函数即可;

单链表函数接口:

//动态申请一个节点
SLNode* BuySListNode(SLTDataType x);
//单链表打印
void SListPrint(SLNode* plist);
//单链表尾插
void SListPushBack(SLNode** pplist, SLTDataType x);
//单链表头插
void SListPushFront(SLNode** pplist, SLTDataType x);
//单链表尾删
void SListPopBack(SLNode** pplist);
//单链表头删
void SListPopFront(SLNode** pplist);
//单链表查找
void SListFind(SLNode* plist, SLTDataType x);
//单链表在pos位置之后插入
void SListInsertAfter(SLNode* pos, SLTDataType x);
//单链表pos位置之后删除
void SListEraseAfter(SLNode* pos);

2.1动态申请一个结点

SLNode* BuySListNode(SLTDataType x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
		newnode->data = x;
		newnode->next = NULL;
	return newnode;
}

申请结点用malloc函数,用法:(强制类型转换)malloc (结点占内存的大小)。在VS2022,2019中,malloc函数可能开辟空间失败返回空指针(但基本上不会失败),所以用if语句判断一下,不然编译器可能会给你打绿色的波浪线。 记得引头文件stdlib.h

2.2单链表打印

void SListPrint(SLNode* phead)
{
	SLNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

打印单链表很简单,将结点中的数据打印,然后指向下一个结点,直到下一个结点为空。

2.3单链表尾插

void SListPushBack(SLNode** pplist, SLTDataType x)
{
  SLNode* newnode = BuySListNode(x);
  if (*pplist == NULL)
  {
    *pplist = newnode;
  }
  else
  {
    SLNode* cur = *pplist;
    while (cur->next)
    {
      cur = cur->next;
    }
    cur->next = newnode;
  }
}

尾插中,如果第一个结点为空,则直接将新结点给第一个结点;不为空,则找单链表最后一个结点的位置。
尾插时,第一个结点为空,需要改变第一个结点,所以需要传地址,传指针的地址,用二级指针接收。

2.4单链表头插

void SListPushFront(SLNode** pplist, SLTDataType x)
{
  SLNode* newnode = BuySListNode(x);
  if (*pplist == NULL)
  {
    *pplist = newnode;
  }
  else 
  {
    newnode->next = *pplist;
    *pplist = newnode;
  }
}

头插时,头指针必改变,所以传地址。

2.5单链表尾删

void SListPopBack(SLNode** pplist)
{
  if (*pplist == NULL)
  {
    printf("单链表为空,不能删除!\n");
  }
  else if (*(pplist)->next == NULL)
  {
    free(*pplist);
    *pplist = NULL;
  }
  else 
  {
    SLNode* cur = *pplist;
    while (cur->next->next)
    {
      cur = cur->next;
    }
    free(cur->next);
    cur->next = NULL;
  }
}

尾删时,链表可能为空,可能有一个结点,也可能有很多结点,不同的的条件用不同的方法处理即可。当有很多结点时,我们需要找到最后一个结点的前一个,所以循环条件为cur->next->next。

2.6单链表头删

void SListPopFront(SLNode** pplist)
{
  if (*pplist == NULL)
  {
    printf("单链表为空,不能删除!\n");
  }
  else 
  {
    SLNode* cur = (*pplist)->next;
    free(*pplist);
    *pplist = cur;
  }
}

头删这里我用的还是二级指针。

2.7单链表查找

void SListFind(SLNode* plist, SLTDataType x)
{
  SLNode* cur = plist;
  while (cur)
  {
    if (cur->val == x)
    {
      printf("找到了!\n");
      return;
    }
    cur = cur->next;
  }
  printf("找不到\n");
}

查找只需将链表遍历一遍,然后比对就行。

2.8单链表在pos位置之后插入

void SListInsertAfter(SLNode* pos, SLTDataType x)
{
  SLNode* newnode = BuySListNode(x);
  SLNode* cur = pos->next;
  pos->next = newnode;
  newnode->next = cur;
}

先将pos位置的结点记录下来,然后将新结点连接在pos后面,最后将记录下来的结点放在新结点的后面。

2.9单链表pos位置之后删除

void SListEraseAfter(SLNode* pos)
{
  SLNode* cur = pos->next->next;
  free(pos->next);
  pos->next = cur;
}

2.10主函数

int main()
{
	SLNode* plist = NULL;
	for (int i = 0; i < 5; ++i)
	    SListPushBack(&plist, i);
	
	SListPrint(plist);
	return 0;
}

3.单链表和顺序表的区别

不同点顺序表链表
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持;O(N)
任意元素插入或者删除元素可能需要搬移元素,效率低O(N)只需修改指针指向
插入动态顺序表,空间不够时需要扩容没有容量概念
应用场景元素高效存储+频繁访问任意位置插入和删除频繁
缓存利用率
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ly@눈_눈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值