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;
}
运行测试结果: