数据结构--链表(C语言)

概述

在这里插入图片描述

在学习过程中, 以掌握不带头结点的单链表带头节点的双向循环链表为主.
初次接触链表, 总会被头结点所吸引, 其实在链表的代码实现上, 一些链表甚至不需要头结点

原来, 链表实际是被头指针所控制!!!

  • 不带头结点的单链表
    • 记住指针传入必须传二级指针, 因为要改变pHead的指向, pHead最为指针传入函数后会被复制, 然 后函数将改变形参的内容, 而不影响实参pHead保存的地址.
    • 故通过封装 SList, 封装二级指针
    • 单链表的插入只插向当前位置后面由于单向性决定, 而双链表一半会插到前面
    • 单链表的清空与销毁一样
    • 题目中若未说明, 则指的是不带头结点的链表
  • 带头结点的双向循环链表
    • 除Init, Destroy其他函数不用穿二级指针, 应为pHead指向永远为头结点, 指针指向不变, 改变的是头结点的指向
    • 不建议头结点存放链表的信息, 如链表的有效结点的个数, 因为若数据类型为char, 则只能保存256个个数

谨记为什么不带头的链表要传二级指针, 而带头的链表只用传

  • 举个例子:
void func(int* pa1, int* pb2)
{
	int* tmp = pa1;
	pa1 = pb2;
	pb2 = tmp;
}
// 想通过形参改变外部实参的话, 必须传外部实参的地址
// 这里交换了指针, pa1是pa的拷贝, 内容变成pb的内容但是并未影响实参
主函数:
	int a = 5, b = 6;
	int* pa = &a;
	int* pb = &b;
	func(pa, pb);
	printf("%d \n", *pa);// 结果任为5

结论: 改变指针的指向必须传二级指针

  • 无头链表的头指针直接指向第一个节点, 若改变头指针的指向必须传二级指针
  • 带头的链表头指针指向头结点, 其指向不会改变, 变的是头结点的指向

无头结点单链表实现代码:

  • 头文件
#include <stdio.h>
typedef int SDataType;

typedef struct SListNode
{
	SDataType _data;
	struct SListNode* _pNext;
}Node, *PNode;

typedef struct SList
{
	PNode _pHead;
}SList;
// 一个单链表的结构体, 传来传去比较爽
// 用于保存链表, 但不是头结点!也不是第一个节点!
// _pHead指向第一个节点
// 封装了二级指针, 否则要传送二级指针

void SListInit(SList* s);
void SListDestory(SList* s);
void SListPushBack(SList* s, SDataType data);
void SListPopBack(SList* s);
void SListPushFront(SList* s, SDataType data);
void SListPopFront(SList* s);
void SListInsert(PNode pos, SDataType data);
void SListErase(SList* s, PNode pos);
PNode SListFind(SList* s, SDataType data);
void SListRemove(SList* s, SDataType data);	// 移除链表中第一个内容为data的元素
void SListRemoveAll(SList* s, SDataType data);	// 移除链表中所有内容为data的元素
size_t SListSize(SList* s);
int SListEmpty(SList* s);
void PrintSList(SList* s);
  • 实现
#include "SList.h"
#include <assert.h>
#include <stdio.h>
#include <malloc.h>

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

void SListDestory(SList* s)
{
	assert(s);
	PNode pCur = s->_pHead;
	while (pCur)
	{
		SListPopFront(s);
		pCur = s->_pHead;
	}
}

// 用于创建一个新节点
PNode BuySListNode(SDataType data)
{
	PNode pCur = (PNode)malloc(sizeof(Node));
	pCur->_data = data;
	pCur->_pNext = NULL;
	return pCur;
}

void SListPushBack(SList* s, SDataType data)
{
	assert(s);
	PNode pNewPNode = BuySListNode(data);
	if (NULL == s->_pHead)
	{
		// 空链表
		s->_pHead = pNewPNode;
	}
	else
	{
		// 链表非空
		// 找链表中最后一个节点
		PNode pCur = s->_pHead;
		while (pCur->_pNext)
		{
			pCur = pCur->_pNext;
		}
		pCur->_pNext = pNewPNode;
	}
}

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

		free(pCur);
		pPre->_pNext = NULL;
	}
}

void SListPushFront(SList* s, SDataType data)
{
	assert(s);
	PNode pNewNode = BuySListNode(data);
	pNewNode->_pNext = s->_pHead;
	s->_pHead = pNewNode;
}

void SListPopFront(SList* s)
{
	assert(s);
	if (NULL == s->_pHead)
	{
		return;
	}
	PNode pDelNode = s->_pHead;
	s->_pHead = pDelNode->_pNext;
	free(pDelNode);
}

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

void SListErase(SList* s, PNode pos)
{
	// 删除Pos指向, 必须找到前一个
	assert(s);
	if (NULL == pos || NULL == s->_pHead)
	{
		return;
	}
	if (pos == s->_pHead)
	{
		s->_pHead = pos->_pNext;
	}
	else
	{
		PNode pPrePos = s->_pHead;
		while (pPrePos && pPrePos->_pNext != pos) // 找到pos前一个
		{										  // 判断pPrePos是否存在, 为了防止pos可能与s不是一个链表
			pPrePos = pPrePos->_pNext;
		}
		if (pPrePos)
		{
			pPrePos->_pNext = pos->_pNext;
		}
	}
	free(pos);
}

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;
}

// 移除链表中第一个值为data的元素
void SListRemove(SList* s, SDataType data)
{
	assert(s);
	if (NULL == s->_pHead)
	{
		return;
	}
	PNode pCur = s->_pHead;
	PNode pPre = NULL;
	while (pCur)
	{
		if (pCur->_data == data)
		{
			if (pCur == s->_pHead)
			{
				s->_pHead->_pNext = pCur->_pNext;
			}
			else
			{
				pPre->_pNext = pCur->_pNext;
			}
			free(pCur);
			return;
		}
		else
		{
			pPre = pCur;
			pCur = pCur->_pNext;
		}
	}
}

void SListRemoveAll(SList* s, SDataType data)
{
	assert(s);
	if (NULL == s->_pHead)
	{
		return;
	}
	PNode pCur = s->_pHead;
	PNode pPre = NULL;
	while (pCur)
	{
		if (pCur->_data == data)
		{
			if (NULL == pPre)
			{
				s->_pHead->_pNext = pCur->_pNext;
				free(pCur);
				pCur = s->_pHead;
			}
			else
			{
				pPre->_pNext = pCur->_pNext;
				free(pCur);
				pCur = pPre->_pNext;
			}
		}
		else
		{
			pPre = pCur;
			pCur = pCur->_pNext;
		}
	}
}

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 PrintSList(SList* s)
{
	assert(s);
	PNode pCur = s->_pHead;
	while (pCur)
	{
		printf("%d--->", pCur->_data);
		pCur = pCur->_pNext;
	}
	printf("NULL\n");
}

有头结点双向循环链表实现代码:

  • 头文件
typedef int DLDataType;

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

void DListInit(PDLNode* pHead);
void DListDestroy(PDLNode* pHead);
PDLNode BuyDListNode(DLDataType data);
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);
  • 实现
#include "DList.h"
#include <stdio.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;
}

void DListDestroy(PDLNode* pHead)
{
	// 改变指向, 二级指针
	DListClear(*pHead);
	free(*pHead);
	(*pHead) = NULL;
}

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

void DListPushBack(PDLNode pHead, DLDataType data)
{
	assert(pHead);
	PDLNode pNewNode = BuyDListNode(data);
	pNewNode->_pPre = pHead->_pPre;
	pNewNode->_pNext = pHead;
	pHead->_pPre = pNewNode;
	pNewNode->_pPre->_pNext = pNewNode;
	
}
void DListPopBack(PDLNode pHead)
{
	assert(pHead);
	if (pHead->_pNext == pHead)
	{
		return;
	}
	PDLNode pDelNode = pHead->_pPre;
	pDelNode->_pPre->_pNext = pDelNode->_pNext;
	pDelNode->_pNext->_pPre = pDelNode->_pPre;
	free(pDelNode);
}

void DListPushFront(PDLNode pHead, DLDataType data)
{
	assert(pHead);
	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->_pNext == pHead)
	{
		return;
	}

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

	pNewNode->_pPre = pos->_pPre;
	pNewNode->_pNext = pos;
	pNewNode->_pPre->_pNext = pNewNode;
	pNewNode->_pNext->_pPre = pNewNode;
	
}

void DListErase(PDLNode pos)
{
	if (NULL == pos)
	{
		return;
	}
	pos->_pPre->_pNext = pos->_pNext;
	pos->_pNext->_pPre = pos->_pPre;
	free(pos);
}
void DListClear(PDLNode pHead)
{
	// 清空, 不删除头结点
	assert(pHead);
	PDLNode pCur = pHead->_pNext;
	while (pCur != pHead)
	{
		pHead->_pNext = pCur->_pNext;
		free(pCur);
		pCur = pHead->_pNext;
	}
	pHead->_pNext = pHead;
	pHead->_pPre = pHead;
}

void PrintDList(PDLNode pHead)
{
	PDLNode pCur = pHead;
	while (pCur->_pNext && pCur->_pNext != pHead)
	{
		printf("%d  ", pCur->_pNext->_data);
		pCur = pCur->_pNext;
	}
}
发布了53 篇原创文章 · 获赞 46 · 访问量 7230

猜你喜欢

转载自blog.csdn.net/new_bee_01/article/details/102600266
今日推荐