単一リンクリストのナレッジポイント

目次

1.1 リンクリストの概念と構造

1.2 リンクリストの分類

1.3 リンクリストの実装


知らないこと、珍しいことは、隠さずに理解してから使いこなしてください。


1.1 リンクリストの概念と構造

  リンク リストは、 物理的な記憶構造における 不連続かつ非順次の記憶構造であり、データ要素の 論理的順序は、リンク リスト内のポインタのリンク順序によって実現されます(アドレスは必ずしも連続しているとは限りません)。

1.2 リンクリストの分類

(1)一方向または双方向

(2)主導権を握るか、主導権を握らないか

(3)環状または非環状

1.3 リンクリストの実装

一方向、ヘッドレス、ループなし

SList.h

#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>


typedef int SLTDateType;

//单链表中,定义一个结构体,结构体里面有两个结构体成员,一个是数据,一个是指针(指针指向一个结构体),
// 这个指针的类型是一个结构体,这个结构体又和自己类型一样,所以结构体有的自引用
typedef struct SListNode
{
	SLTDateType date;//数据
	struct SListNode* next;//储存下一个节点的地址
}SListNode;
//知识点结构体的自引用方式

//单链表不需要初始化,因为单链表刚开始只有一个指针
void SListPrint(SListNode* phead);//打印
//尾插
void SListPushBack(SListNode** pphead, SLTDateType x);
//头插
void SListPushFront(SListNode** pphead, SLTDateType x);
//尾删
void SListPopBack(SListNode** pphead);//需要传递的是头部结构体的地址的地址,当尾删的时候,如果单链表就有一个值,那么进行尾删的时候,需要改变头部结构体地址
//头删
void SListPopFront(SListNode** pphead);
//查找
SListNode* SListFind(SListNode* phead, SLTDateType x);
//前插入
void SListInsert(SListNode** pphead, SListNode* pos, SLTDateType x);
//后插入
void SListInsertAfter(SListNode* pos, SLTDateType x);
//删除
void SListErase(SListNode** pphead, SListNode* pos);
//删除后面
void SListEraseAfter(SListNode** pphead);
//销毁
void SListDestory(SListNode** pphead);

SList.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"


//打印
void SListPrint(SListNode* phead)
{
	//assert(phead);//这里不需要断言,因为单链表可能是空链表
	SListNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->date);
		cur = cur->next;
	}
	printf("NULL\n");
}

//一个节点的创建
SListNode* BuySListNode(SLTDateType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SLTDateType));
	if (newnode == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	else
	{
		newnode->date = x;
		newnode->next = NULL;
	}
	return newnode;
}

//尾插
void SListPushBack(SListNode** pphead, SLTDateType x)//当链表是空的时候,尾插,相当于头插,需要改变头部的地址,改变地址,需要传递头部地址的地址【形参的改变不影响实参】
//需要改变谁,就需要传谁的地址
{
	assert(pphead);
	SListNode* newnode = BuySListNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}
//头插//改变头部地址就需要传二级指针
void SListPushFront(SListNode** pphead, SLTDateType x)
{
	assert(pphead);
	SListNode* newnode = BuySListNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}


//尾删//要把倒数第二个值的next变成NULL,所以需要倒数第二个结构体的地址,才能改变(形参的改变,不改变实参)【每一个结构体,相当于结构体传参】
//没有节点,一个节点,许多节点
void SListPopBack(SListNode** pphead)
{
	assert(pphead);
	if (*pphead == NULL)//空
	{
		return;
	}
	else if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SListNode* prev = NULL;
		SListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			prev = tail;//倒数第二个
			tail = tail->next;//倒数第一个
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;
	}
}
//头删
void SListPopFront(SListNode** pphead)
{
	assert(pphead);
	if (*pphead == NULL)
	{
		return;
	}
	else//一个值和很多值
	{
		SListNode* front = NULL;
		front = (*pphead)->next;
		free(*pphead);
		*pphead = front;
	}
}

//查找
SListNode* SListFind(SListNode* phead, SLTDateType x)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		if (cur->date == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//插入,在某个数字前插入//首先用find找某个数的地址,然后再在地址处插入。,
void SListInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SListPushFront(pphead, x);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SListNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}
//在insert之后插入
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
	assert(pos);
	SListNode* next = pos->next;
	SListNode* newnode = BuySListNode(x);
	pos->next = newnode;
	newnode->next = next;
}

//删除
void SListErase(SListNode** pphead, SListNode* pos)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SListPopFront(pphead);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		pos = NULL;
		free(pos);
	}
}

//删除后面
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	if (pos->next == NULL)
	{
		return;
	}
	else
	{
		SListNode* next = pos->next;
		pos->next = next->next;
		free(next);
		next = NULL;
	}
}

//销毁
void SListDestory(SListNode** pphead)
{
	assert(pphead);
	SListNode* cur = *pphead;
	SListNode* next = NULL;
	while (cur->next != NULL)
	{
		next = cur->next;
		free(cur);
		cur = NULL;
	}
	*pphead = NULL;
}


単一リンク リストは最初に構造体へのポインタを定義するため、構造体の初期化は必要ありませんが、シーケンス テーブルは最初に構造体を定義するため、構造体の初期化が必要です。(シーケンステーブル初期化時は値は空ですが、容量とサイズは確保可能です) (シングルリンクリスト、値がない場合は構造体ポインタ(先頭アドレス)がNULLとなります)

おすすめ

転載: blog.csdn.net/m0_57388581/article/details/131146042