在这里插入代码片
1. 熟悉什么是链表,链表的分类?
`链表是一种物理存储结构上非连续,顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,
2.链表带头结点和不带头结点的区别?
带头结点可以快速定位链表,在插入和删除第一个结点时都会更加方便.,带头结点时,头指针指向头结点,不带头结点时,头指针指向第一个结点的地址.
3.以链表中最常见的2中链表为例,进行一些操作:
不循环单链表
#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);
//尾插
void SListPushBack(SList* s, SDataType data);
//尾删
void SListPopBack(SList* s);
//头插
void SListPushFront(SList* s, SDataType data);
//头删
void SListPopFront(SList* s);
//任意位置的插入
void SListInsert(SList*s,PNode pos, SDataType data);
//任意位置的删除
void SListErase(SList* s, PNode pos);
//结点数
int SListSize(SList* s);
//判空
int SListEmpty(SList* s);
//删除第一个值为data的结点
void SListRemove(SList* s, SDataType data);
#include "SList.h"
#include <stdio.h>
#include <assert.h>
void SListInit(SList* s)
{
assert(s);
s->_pHead = NULL;
}
PNode BuySListNode(SDataType data)
{
PNode pNewNode = (PNode)malloc(sizeof(PNode));
if (pNewNode == NULL)
{
assert(0);
return NULL;
}
pNewNode->_data = data;
pNewNode->_pNext = NULL;
return pNewNode;
}
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;
}
}
void SListPopBack(SList* s)
{
assert(s);
if (s->_pHead == NULL)
//空链表
return;
else if(NULL ==s->_pHead->_pNext)
{
//一个节点
free(s->_pHead);
s->_pHead;
}
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 (s->_pHead == NULL);
//空链表
else if (s->_pHead->_pNext == NULL)
{
free(s->_pHead);
}
else
{
s->_pHead = s->_pHead->_pNext;
free(s->_pHead);
}
return;
}
void SListInsert(SList* s,PNode pos, SDataType data)
{
assert(s);
if (pos == NULL)
return;
PNode pNewNode = BuySListNode(data);
pNewNode->_pNext = pos->_pNext;
pos->_pNext = pNewNode;
}
void SListErase(SList* s, PNode pos)
{
assert(s);
if (s->_pHead == NULL||pos == NULL)
return;
else if(s->_pHead==pos)
{
s->_pHead = s->_pHead->_pNext;
}
else
{
PNode pPrePos = s->_pHead;
while (pPrePos->_pNext != pos)
pPrePos = pPrePos->_pNext;
pPrePos->_pNext = pos->_pNext;
}
free(pos);
}
int SListSize(SList* s)
{
assert(s);
if (s->_pHead == NULL)
return 0;
else
{
int count = 1;
PNode pCur = s->_pHead;
while (pCur->_pNext)
{
pCur = pCur->_pNext;
++count;
return count;
}
}
}
int SListEmpty(SList* s)
{
assert(s);
return NULL == s->_pHead;
}
void SListRemove(SList* s, SDataType data)
{
assert(s);
if (s->_pHead == NULL)
return;
PNode pPre = NULL;
PNode pCur = s->_pHead;
while (pCur)
{
if (pCur->_data == data)
{
if (pCur == s->_pHead)
{
s->_pHead = pCur->_pNext;
}
else
{
pPre->_pNext = pCur->_pNext;
}
free(pCur);
break;
}
else
{
pPre = pCur;
pCur = pCur->_pNext;
}
}
return;
}
循环双链表
#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 DLishInsert(PDLNode pos, DLDataType data);
void DLishErase(PDLNode pos);
void DLishClear(PDLNode pHead);
void DLishDestroy(PDLNode* pHead);
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "DList.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 BuyDistNode(DLDataType data)
{
PDLNode pNewNode = (PDLNode)malloc(sizeof(DLNode));
if (NULL == pNewNode)
{
assert(0);
return;
}
pNewNode->_data = data;
pNewNode->_pNext = NULL;
pNewNode->_pPre = NULL;
return pNewNode;
}
void DListPushBack(PDLNode pHead, DLDataType data)
{
PDLNode pNewNode = BuyDistNode(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->_pNext = pHead->_pNext;
pNewNode->_pPre = pHead;
pHead->_pNext = pNewNode;
pNewNode->_pNext->_pPre = pNewNode;
}
void DListPopFront(PDLNode pHead)
{
assert(pHead);
if (pHead->_pNext == pHead)
return;
PDLNode pDelNode = pHead->_pNext;
pHead->_pNext = pDelNode->_pNext;
pDelNode->_pNext->_pPre = pHead;
free(pDelNode);
}
void DLishInsert(PDLNode pos, DLDataType data)
{
if (pos==NULL)
return;
PDLNode pNewNode = BuyDListNode(data);
pNewNode->_pNext = pos;
pNewNode->_pPre = pos->_pPre;
pos->_pPre = pNewNode;
pNewNode->_pPre->_pNext = pNewNode;
}
void DLishErase(PDLNode pos)
{
if (pos == NULL)
return;
pos->_pNext->_pPre = pos->_pPre;
pos->_pPre->_pNext = pos->_pNext;
free(pos);
}
void DLishClear(PDLNode pHead)
{
PDLNode pCur = pHead->_pNext;
while (pCur != pHead)
{
pHead->_pNext = pCur->_pNext;
free(pCur);
pCur = pHead->_pNext;
}
pHead->_pNext;
pHead->_pPre = pHead;
}
void DLishDestroy(PDLNode* pHead)
{
DListClear(*pHead);
free(*pHead);
*pHead = NULL;
}
链表与顺序表的区别:
1,首先:他们名称不同(^ - ^);
2,尾插和尾删时:
顺序表的时间复杂度为O(1),而链表中不带头结点的链表时间复杂度为O(N),循环链表为O(1);
3.在任意位置插入和删除时:
顺序表的时间复杂度为O(N),而链表的时间复杂度为O(1);
4.顺序表支持随机访问,而链表不支持随机访问.
5,关于底层空间:顺序表的底层空间一般连续,而链表的底层空间不连续
6.顺序表在插入元素时可能需要扩容,而链表不需要.
7.在空间利用率方面,顺序表除非扩容,否则不需要申请空间,而链表每次插入都需要申请空间.
8.顺序表的缓存利用率高
9.在应用方面不同