1. 熟悉什么是链表,链表的分类?
链表(链式存储)
假如我们现在要存放一些物品,但是没有足够大的空间将所有的物品一次性放下(电脑中使用链式存储不是因为内存不够先事先说明一下...,具体原因后续会说到),同时设定我们因为脑容量很小,为了节省空间,只能记住一件物品位置。此时我们很机智的找到了解决方案:存放物品时每放置一件物品就在物品上贴一个小纸条,标明下一件物品放在那里,只记住第一件物品的位置,寻找的时候从第一件物品开始寻找,通过小纸条我们可以找到所有的物品,这就是链式存储。链表实现的时候不再像线性表一样只存储数据即可,还有下一个数据元素的地址,因此先定义一个节点类(Node),记录物品信息和下一件物品的位置,我们把物品本身叫做数据域,存储下一件物品地址信息的小纸条称为引用域。链表结构示意图如下: 寻找物品的时候发现了一个问题,我们从一件物品找下一件物品的时候很容易,但是如果要找上一件物品就得从头开始找,真的很麻烦。为了解决这个问题我们又机智了一把,模仿之前的做法,在存放物品的时候多放置一个小纸条记录上一件物品的位置,这样就可以很快的找到上一件物品了。我们把这种方式我们称为双向链表,前面只放置一张小纸条的方式称为单向链表。
2. 熟悉链表带头结点和不带头结点的区别? (后面解释)
带头节点:head-> p1->p2->p3 ->p1->p2->p3-> p1.....
不带头节点: p1->p2->p3 ->p1->p2->p3-> p1.....
却别还不明显吗?带头节点可以方便,快速的定位链表第1个节点
比如循环链表的时候,删除p1 的时候:
head->next = p2;
p3->next = head->next; ok?
free(p1);
思路很清晰,链表开始的第1个节点现在就是head->next 即 p2
否则没有头节点:
p3->next = p1->next;
free(p1);
3. 完成单链表的以下基本操作:
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);
运行结果如下
Single_list.h
#pragma once
#include <stdio.h>
#include<stdlib.h>
typedef int Datatype;
typedef struct ListNode
{
struct ListNode* _pnext;
Datatype _pdata;
}Node,*pNode;
void SListinit(pNode* pHead);
void Printlist(pNode* pHead);
pNode BuySListNode(Datatype data);
void SListPusfhBack(pNode* pHead, Datatype data);
void SListPopBack(pNode* pHead);
void SListPushFront(pNode* pHead, Datatype data);
void SListPopFront(pNode* pHead);
void SListInsert(pNode* pHead, pNode pos, Datatype data);
int SListEmpty(pNode* pHead);
int SListSize(pNode* pHead, Datatype data);
void SListErase(pNode* pHead, pNode pos);
pNode SListFind(pNode* pHead, Datatype data);
void SListDestroy(pNode* pHead);
Single_list.c
#include "single_list.h"
#include<stdio.h>
#include<assert.h>
void SListinit(pNode* pHead) {
assert(pHead);
*pHead = NULL;
}
void Printlist(pNode* pHead) {
pNode pCur = *pHead;
if (pCur == NULL)
{
printf("链表为空!\n");
return;
}
while (pCur) {
printf("%d->", pCur->_pdata);
pCur = pCur->_pnext;
}
printf("NULL\n");
}
pNode BuySListNode(Datatype data) {
pNode pNewNode = (pNode)malloc(sizeof(Node));
if (NULL == pNewNode) {
//
perror("pNewNode");
//
exit(EXIT_FAILURE);
}
pNewNode->_pdata = data;
pNewNode->_pnext = NULL;
return pNewNode;
}
void SListPushBack(pNode* pHead,Datatype data) {
pNode pCur = *pHead;
assert(pHead);
if (NULL == pCur) {
//如果链表为空直接插入
*pHead = BuySListNode(data);
}
//链表不为空找到最后一个再插
else {
while (pCur->_pnext) {
pCur = pCur->_pnext;
}
pCur->_pnext = BuySListNode(data);
}
}
void SListPopBack(pNode* pHead) {
pNode pCur = *pHead;
pNode pTail = NULL;
assert(pHead);
if (NULL == *pHead) {
return;
}
else if(NULL==(*pHead)->_pnext){
free(*pHead);
*pHead = NULL;
}
else {
while (pCur->_pnext) {
pTail = pCur;
pCur = pCur->_pnext;
}
pTail->_pnext = NULL;
free(pCur);
pCur = NULL;
}
}
void SListPushFront(pNode* pHead, Datatype data) {
pNode pNewNode = BuySListNode(data);
assert(pHead);
pNewNode->_pnext = *pHead;
*pHead = pNewNode;
}
void SListPopFront(pNode* pHead) {
pNode pDelNode = *pHead;
if (NULL == *pHead) {
assert(pHead);
return;
}
else {
*pHead = pDelNode->_pnext;
free(pDelNode);
}
}
void SListInsert(pNode* pHead, pNode pos, Datatype data) {
pNode pNewNode = NULL;
if (NULL == pHead || NULL == pos) {
printf("链表不存在!\n");
return;
}
else {
pNewNode = BuySListNode(data);
pNewNode->_pnext = pos->_pnext;
pos->_pnext = pNewNode;
}
}
int SListEmpty(pNode* pHead) {
if (NULL == pHead) {
return 1;
}
else {
return 0;
}
}
int SListSize(pNode* pHead, Datatype data)//找到值为data的节点个数
{
int count = 0;
pNode pCur = *pHead;
if (NULL == pHead)
{
printf("链表为空\n");
return 0;
}
while (pCur)
{
if (pCur->_pdata == data) {
count++;
}
pCur = pCur->_pnext;
}
return count;
}
void SListErase(pNode* pHead, pNode pos)
{
pNode pDel = NULL;
assert(pHead);
if (pHead == NULL || NULL == pos)
{
printf("输入错误\n");
return;
}
else
{
pDel = pos->_pnext;
pos->_pdata = pDel->_pdata;
pos->_pnext = pDel->_pnext;
free(pDel);
pDel = NULL;
}
}
pNode SListFind(pNode* pHead, Datatype data)
{
pNode pcur = *pHead;
if (NULL == pHead) {
printf("链表为空!\n");
return NULL;
}
while (pcur)
{
pcur = pcur->_pnext;
if (pcur->_pdata == data) {
return pcur;
}
}
return NULL;
}
void SListDestory(pNode* pHead)
{
pNode pcur = *pHead;
pNode pnext = NULL;
assert(pHead);
if (NULL == pHead)
{
return;
}
else
{
*pHead = NULL;
while (pcur)
{
pnext = pcur->_pnext;
free(pcur);
pcur = pnext;
}
}
}
int main()
{
pNode SList, pos;
SListinit(&SList);
printf("初始化之后的链表为: ");
Printlist(&SList);
SListPushBack(&SList, 1);
SListPushBack(&SList, 2);
SListPushBack(&SList, 3);
SListPushBack(&SList, 4);
SListPushBack(&SList, 5);
SListPushBack(&SList, 6);
printf("尾插之后的链表为: ");
Printlist(&SList);
SListPopBack(&SList);
printf("尾删之后的链表为: ");
Printlist(&SList);
SListPushFront(&SList, 0);
printf("头插后的链表为: ");
Printlist(&SList);
SListPopFront(&SList);
printf("头删后的链表为: ");
Printlist(&SList);
printf("寻找节点为3的个数:%d\n", SListSize(&SList, 3));
pos = SListFind(&SList, 3);//pos为节点,通过Find的=函数返回一个节点进行传参
SListInsert(&SList, pos, 9);
printf("在节点为3的位置后插入9:\n");
Printlist(&SList);
SListErase(&SList, pos);
printf("删除值为3的节点:\n");
Printlist(&SList);
system("pause");
return 0;
}