单链表

72 篇文章 0 订阅
40 篇文章 0 订阅

1…链表的分类?
链表是一种物理存储结构上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
链表一共分为8种。1.单向、双向。2.带头、不带头。3.循环、不循环。由这几种情况组合而成。

常见的是不带头非循环单链表、带头循环双向链表。

2… 熟悉链表带头结点和不带头结点的区别?
带头节点,用一个特殊的节点存放指向链表第一个元素的指针,如果该指针为空就说明该链表没有节点,为空链表。
不带头节点,第一个元素包含数据和指向下一个元素的指针。它就是该链表的起点。
不带头非循环单链表的基本操作:
SList.h文件

#pragma once
typedef int SDataType;

// 链表的节点 
typedef struct SListNode
{
	SDataType _data;
	struct SListNode* _pNext;
}Node, *PNode;


// 链表的结构,给一个头指针保存链表第一个节点的地址 
typedef struct SList
{
	PNode _pHead; // 指向链表中的第一个节点 
}SList, *PSList;


// 链表的初始化 
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);

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

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

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

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

//打印函数
void PritfSList(SList* s);

SList.c文件

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "SList.h"


// 链表的初始化 
void SListInit(SList* s) {
	assert(s);
	s->_pHead = NULL;
}
//创建新的节点
PNode BuySListNode(SDataType data) {
	PNode pNewNode = (PNode)malloc(sizeof(Node));

	if (NULL == pNewNode) {
		assert(0);
		return;
	}
	pNewNode->_data = data;
	pNewNode->_pNext = NULL;
	return pNewNode;
}

// 在链表s最后一个节点后插入值为data的节点 
void SListPushBack(SList* s, SDataType data) {
	assert(s);
	PNode pNewNode = BuySListNode(data);//创建一个新的节点
	if (NULL == s->_pHead) {
		s->_pHead = pNewNode;//如果链表为空,则让头节点指向新建立的节点
	}
	else
	{
		PNode pCur = s->_pHead;//创建一个变量用于寻找
		while (pCur->_pNext) {
			pCur = pCur->_pNext;//搜索最后一个节点为空时停下
		}
		pCur->_pNext = pNewNode;
	}
}

// 删除链表s最后一个节点 
void SListPopBack(SList* s) {
	assert(s);
	PNode pCur = s->_pHead;
	if (pCur == NULL) {
		return;
	}
	if (pCur->_pNext ==NULL) {
		free(pCur);
		s->_pHead = NULL;
		return;
	}
	while (pCur->_pNext->_pNext) {
		pCur = pCur->_pNext;//寻找下下一个元素
	}
	free(pCur->_pNext);//删除指针后需将其置空
	pCur->_pNext = NULL;
}

// 在链表s第一个节点前插入值为data的节点 
void SListPushFront(SList* s, SDataType data) {
	assert(s);
	///*if (s->_pHead == NULL) {
	//	SListPushBack(s, data);
	//}
	//else
	//{
	//	PNode pNewNode = BuySListNode(data);
	//	pNewNode->_pNext = s->_pHead;
	//	s->_pHead->_pNext = pNewNode;
	//}*/
	PNode pNewNode = BuySListNode(data);
	pNewNode->_pNext = s->_pHead;
	s->_pHead = pNewNode;
}

// 删除链表s的第一个节点 
void SListPopFront(SList* s) {
	assert(s);
	if (NULL == s->_pHead) {
		return;
	}
	PNode pDelNode = s->_pHead;
	s->_pHead = s->_pHead->_pNext;
	free(pDelNode);
}

// 在链表的pos位置后插入值为data的节点 
void SListInsert(PNode pos, SDataType data) {
	if (pos == NULL) {
		return;
	}
	PNode pNewNode = BuySListNode(data);
	pNewNode->_pNext = pos->_pNext;
	pos->_pNext = pNewNode;
}

// 删除链表s中pos位置的节点 
void SListErase(SList* s, PNode pos) {
	assert(s);
	if (NULL == pos || NULL == s->_pHead) {
		return;
	}
	if (pos == s->_pHead) {
		s->_pHead = s->_pHead->_pNext;
	}
	else
	{
		PNode pPrePos = s->_pHead;
		while (pPrePos && pPrePos->_pNext!=pos) 
			pPrePos = pPrePos->_pNext;
		if (pPrePos)
			pPrePos->_pNext = pPrePos->_pNext->_pNext;
	}
	free(pos);
}

// 在链表中查找值为data的节点,找到返回该节点的地址,否则返回NULL 
PNode SListFind(SList* s, SDataType data) {
	assert(s);
	PNode pCur = s->_pHead;
	while (pCur) {
		//pCur = pCur->_pNext;
		//查找时考虑每个元素都被遍历到,条件顺序考虑好
		if (data == pCur->_data) {
			return pCur;
		}
		pCur = pCur->_pNext;
	}
	return NULL;
}

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

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

// 将链表中有效节点清空 
void SListClear(SList* s) {
	assert(s);
	while (SListSize(s)) {
		SListPopBack(s);
	}
	free(s->_pHead);
}

// 销毁链表 
void SListDestroy(SList* s) {
	assert(s);
	while (SListSize(s)) {
		SListPopBack(s);
	}
	free(s->_pHead);
}

void PritfSList(SList* s) {
	assert(s);
	if (s->_pHead == NULL) {
		printf("NULL\n");
		return;
	}
	PNode pCur = s->_pHead;
	while (pCur) {
		printf("%d---->",pCur->_data);
		pCur = pCur->_pNext;
	}
	printf("\n");
}
int main() {

	SList s;
	SListInit(&s);
	SListPushBack(&s, 1);
	SListPushBack(&s, 2);
	SListPushBack(&s, 3);
	SListPushBack(&s, 4);
	SListPushBack(&s, 5);
	SListPushBack(&s, 6);
	PritfSList(&s);
	SListPopBack(&s);
	PritfSList(&s);
	SListPopFront(&s);
	PritfSList(&s);
	SListPushFront(&s, 9);
	
	PritfSList(&s);
	printf("%d\n",SListEmpty(&s));

	printf("%d\n",SListSize(&s));

	printf("%p\n", SListFind(&s, 9));
	printf("%p\n", SListFind(&s, 2));
	printf("%p\n", SListFind(&s, 3));
	printf("%p\n", SListFind(&s, 4));
	printf("%p\n", SListFind(&s, 5));

	SListInsert(SListFind(&s, 3), 8);
	PritfSList(&s);

	SListErase(&s, SListFind(&s, 3));
	PritfSList(&s);

	SListClear(&s);
	PritfSList(&s);

	SListDestroy(&s);
	PritfSList(&s);
	system("pause");
	return 0;
}

分步测试运行结果:
在这里插入图片描述
带头循环双向链表的基本操作:
DList.h文件

#pragma once

typedef int DLDataType;


typedef struct DListNode
{
	struct DListNode* _pNext;
	struct DListNode* _pPre;
	DLDataType _data;
}DLNode, *PDLNode;


void DListInit(PDLNode* pHead);
void DListPushBack(PDLNode pHead, DLDataType data);
void DListPopBack(PDLNode pHead);
void DListPushFront(PDLNode pHead, DLDataType data);
void DListPopFront(PDLNode pHead);
void DListInsert(PDLNode pos, DLDataType data);
void DListErase(PDLNode pos);
void DListClear(PDLNode pHead);
void DListDestroy(PDLNode* pHead);

void PrintDList(PDLNode pHead);

DList.c文件

#include "DList.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <malloc.h>

void DListInit(PDLNode* pHead) {
	assert(pHead);
	*pHead = (PDLNode)malloc(sizeof(DLNode));
	if (NULL == *pHead) {
		assert(0);
		return;
	}
	(*pHead)->_pNext = *pHead;
	(*pHead)->_pPre = *pHead;
}

PDLNode BuyDListNode(DLDataType data) {
	PDLNode pNewNode = (PDLNode)malloc(sizeof(DLNode));
	if (pNewNode == NULL) {
		assert(0);
		return NULL;
	}
	
	pNewNode->_pNext = NULL;
	pNewNode->_pPre = NULL;
	pNewNode->_data = data;

	return pNewNode;
}

void DListPushBack(PDLNode pHead, DLDataType data) {
	PDLNode pNewNode = BuyDListNode(data);
	pNewNode->_pNext = pHead;
	pNewNode->_pPre = pHead->_pPre;
	pHead->_pPre->_pNext = pNewNode;
	pHead->_pPre = pNewNode;
}

void DListPopBack(PDLNode pHead) {
	assert(pHead);
	if (pHead == pHead->_pNext) {
		return;
	}
	PDLNode pDelNode = pHead->_pPre;
	pDelNode->_pPre->_pNext = pHead;
	pHead->_pPre = pDelNode->_pPre;
	free(pDelNode);
}

void DListPushFront(PDLNode pHead, DLDataType data) {
	PDLNode pNewNode = BuyDListNode(data);
	pNewNode->_pPre = pHead;
	pNewNode->_pNext = pHead->_pNext;
	pHead->_pNext = pNewNode;
	pNewNode->_pNext->_pPre = pNewNode;
}

void DListPopFront(PDLNode pHead) {
	assert(pHead);
	if (pHead == pHead->_pNext) {
		return;
	}
	PDLNode pDelNode = pHead->_pNext;
	pHead->_pNext = pDelNode->_pNext;
	pDelNode->_pNext->_pPre = pHead;
	free(pDelNode);
}

void DListInsert(PDLNode pos, DLDataType data) {
	if (pos == NULL) {
		return;
	}
	PDLNode pNewNode = BuyDListNode(data);
	pNewNode->_pNext = pos;
	pNewNode->_pPre = pos->_pPre;
	//pos->_pPre->_pNext = pNewNode;
	pos->_pPre = pNewNode;
	pNewNode->_pPre->_pNext = pNewNode;
	
}

void DListErase(PDLNode pos) {
	if (pos == NULL) {
		return;
	}
	
	pos->_pNext->_pPre = pos->_pPre;
	pos->_pPre->_pNext = pos->_pNext;
	free(pos);
	pos == NULL;
}

PDLNode DListFind(DLDataType pos, PDLNode pHead) {
	assert(pHead);
	PDLNode pRet = pHead;
	while (pRet != pHead->_pNext) {
		if (pos == pHead->_data) {
			return pHead;
		}
		pHead = pHead->_pNext;
	}
	return NULL;
}

void DListClear(PDLNode pHead) {
	PDLNode pCur = pHead->_pPre;
	while (pCur != pHead) {
		pCur->_pPre->_pNext = pHead;
		pHead->_pPre = pCur->_pPre;
		free(pCur);
		pCur = pHead->_pPre;
		//pCur->_pNext = pHead->_pNext;
	}
	pHead->_pNext = pHead;
	pHead->_pPre = pHead;
}

void DListDestroy(PDLNode* pHead) {
	DListClear(*pHead);
	free(*pHead);
	*pHead = NULL;
}

void PrintDList(PDLNode pHead) {
	assert(pHead);
	PDLNode pCur = pHead;
	while (pCur != pHead->_pNext) {
		printf("%d---->", pHead->_pNext->_data);
		pHead = pHead->_pNext;
	}
	printf("\n");

}

int main() {

	PDLNode pHead = NULL;
	DListInit(&pHead);
	
	//printf("%p\n", BuyDListNode(2));
	DListPushBack(pHead, 1);
	DListPushBack(pHead, 2);
	DListPushBack(pHead, 3);

	PrintDList(pHead);

	DListPushFront(pHead, 4);
	DListPushFront(pHead, 5);
	DListPushFront(pHead, 6);

	PrintDList(pHead);

	DListPopBack(pHead);
	PrintDList(pHead);

	DListPopFront(pHead);
	PrintDList(pHead);

	DListInsert(pHead, 9);
	PrintDList(pHead);

	//printf("%p\n", DListFind(2, pHead));

	DListErase(DListFind(2,pHead),pHead);
	PrintDList(pHead);

	DListClear(pHead);

	DListDestroy(&pHead);

	system("pause");
	return 0;
}

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值