顺序表和链表的区别
顺序表可以实现下标的随机访问,尾插尾删的效率不错,但插入删除比较麻烦,且增容需要开新的空间,一般呈两倍增长,容易空间浪费。为了实现不扩容,按需申请释放,解决插入删除产生的挪动数据问题,因此引入了链表。
存储
CPU不直接访问内存,一般是访问寄存器(数据小)、三级高速缓存(数据大)
缓存命中:数据在缓存,直接访问;
不命中:数据不在,先加载数据进缓存,在访问
链表
概念
概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
单链表
定义单链表的结构体
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
动态申请一个节点(创建节点)
SListNode* BuySListNode(SLTDateType x)
{
SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
if (tmp == NULL)
{
perror("malloc fail\n");
return;
}
tmp->data = x;
tmp->next = NULL;
return tmp;
}
实现单链表尾插
找的是最后一个节点,并把最后一个节点的下一个指针指向新节点;如果是空链表,就直接指向新节点
void SListPushBack(SListNode** pplist, SLTDateType x)
{
assert(pplist);
SListNode* newnode = BuySListNode(x);
if ((*pplist) == NULL)
{
*pplist= newnode;
}
else
{
SListNode* cur = *pplist;
while (cur->next !=NULL)
{
cur = cur->next;
}
cur->next =newnode;//是把newnode赋给cur->next
}
}
单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
assert(pplist);
//方法2
SListNode* newnode = BuySListNode(x);
SListNode* cur = *pplist;
newnode->next = cur;
*pplist = newnode;
//方法1
/*if ((*pplist)->next == NULL)
{
newnode = *pplist;
}
else
{
SListNode* cur = *pplist;
newnode->next = cur;
newnode = *pplist;
}*/
}
单链表打印
void SListPrint(SListNode* plist)
{
SListNode* cur = plist;
while (cur!=NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
单链表的尾删
要断言是否有节点,没有节点不能删;如果只有一个节点,就直接删;如果存在多个节点,要找倒数第二个节点,把他的下一个节点置为空并释放节点
void SListPopBack(SListNode** pplist)
{
assert(pplist);
assert(*pplist);
SListNode* cur = *pplist,*prev=NULL;
if (cur->next == NULL)
{
free(cur);
cur = NULL;
}
else
{
while (cur->next)//是找倒数第二个结点
{
prev = cur;
cur = cur->next;
}
prev->next = NULL;
free(cur);
cur = NULL;
}
}
单链表头删
void SListPopFront(SListNode** pplist)
{
assert(pplist);
assert(*pplist);
SListNode* cur = *pplist;
if (cur->next == NULL)
{
free(cur);
cur = NULL;
}
else
{
*pplist = cur->next;
free(cur);
cur = NULL;
}
}
查找单链表
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
assert(plist);
SListNode* cur = plist;
while (cur)
{
if (cur->data == x) return cur;//返回地址
cur = cur->next;
}
}
单链表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* cur = BuySListNode(x);
cur->next = pos->next;
pos->next = cur;
}
单链表删除pos位置之后的值
void SListEraseAfter(SListNode* pos)
{
assert(pos);
SListNode* cur = pos->next;
pos->next = cur->next;
free(cur);
}
在pos的前面插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{
assert(pphead);
assert(pos);
//*pphead=pos
if (*pphead == pos)
{//头插
SListPushFront(pphead, x);
}else
{
SListNode* newnode = BuySListNode(x);
SListNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
newnode->next = pos;
cur->next = newnode;
}
}
删除pos位置
void SLTErase(SListNode** pphead, SListNode* pos)
{
assert(pphead);
assert(pos);
SListNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
cur->next = pos->next;
free(pos);
}
void SLTDestroy(SListNode** pphead)
{
assert(pphead);
free(*pphead);//
*pphead = NULL;
}
全部代码以及运行结果
// slist.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
// 动态申请一个节点
SListNode* BuySListNode(SLTDateType x)
{
SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
if (tmp == NULL)
{
perror("malloc fail\n");
return;
}
tmp->data = x;
tmp->next = NULL;
return tmp;
}
// 单链表打印
void SListPrint(SListNode* plist)
{
SListNode* cur = plist;
while (cur!=NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
assert(pplist);
SListNode* newnode = BuySListNode(x);
if ((*pplist) == NULL)
{
*pplist= newnode;
}
else
{
SListNode* cur = *pplist;
while (cur->next !=NULL)
{
cur = cur->next;
}
cur->next =newnode;//是把newnode赋给cur->next
}
}
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
assert(pplist);
SListNode* newnode = BuySListNode(x);
SListNode* cur = *pplist;
newnode->next = cur;
*pplist = newnode;
//不用判断
/*if ((*pplist)->next == NULL)
{
newnode = *pplist;
}
else
{
SListNode* cur = *pplist;
newnode->next = cur;
newnode = *pplist;
}*/
}
// 单链表的尾删
void SListPopBack(SListNode** pplist)
{
assert(pplist);
assert(*pplist);
SListNode* cur = *pplist,*prev=NULL;
if (cur->next == NULL)
{
free(cur);
cur = NULL;
}
else
{
while (cur->next)//是找倒数第二个结点
{
prev = cur;
cur = cur->next;
}
prev->next = NULL;
free(cur);
cur = NULL;
}
}
// 单链表头删
void SListPopFront(SListNode** pplist)
{
assert(pplist);
assert(*pplist);
SListNode* cur = *pplist;
if (cur->next == NULL)
{
free(cur);
cur = NULL;
}
else
{
*pplist = cur->next;
free(cur);
cur = NULL;
}
}
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
assert(plist);
SListNode* cur = plist;
while (cur)
{
if (cur->data == x) return cur;//返回地址
cur = cur->next;
}
}
// 单链表在pos位置之后插入x
// 分析思考为什么不在pos位置之前插入?
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* cur = BuySListNode(x);
cur->next = pos->next;
pos->next = cur;
}
// 单链表删除pos位置之后的值
// 分析思考为什么不删除pos位置?
void SListEraseAfter(SListNode* pos)
{
assert(pos);
SListNode* cur = pos->next;
pos->next = cur->next;
free(cur);
}
// 在pos的前面插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{
assert(pphead);
assert(pos);
//*pphead=pos
if (*pphead == pos)
{//头插
SListPushFront(pphead, x);
}else
{
SListNode* newnode = BuySListNode(x);
SListNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
newnode->next = pos;
cur->next = newnode;
}
}
// 删除pos位置
void SLTErase(SListNode** pphead, SListNode* pos)
{
assert(pphead);
assert(pos);
SListNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
cur->next = pos->next;
free(pos);
}
void SLTDestroy(SListNode** pphead)
{
assert(pphead);
free(*pphead);//
*pphead = NULL;
}
void test1()
{
SListNode* s=NULL;//先初始化
SListPushFront(&s, 11);
SListPushFront(&s, 7);
SListPushFront(&s, 10);
SListPushBack(&s, 8);
SListPushBack(&s, 88);
SListPushBack(&s, 888);
SListPrint(s);//注意传参
printf("\n");
SLTDestroy(&s);
}
void test2()
{
SListNode* s = NULL;//先初始化
SListPushFront(&s, 11);
SListPushFront(&s, 7);
SListPushFront(&s, 10);
SListPushBack(&s, 8);
SListPushBack(&s, 88);
SListPushBack(&s, 888);
SListPushBack(&s, 82);
SListPopBack(&s);
SListPopFront(&s);
SListPrint(s);//注意传参
printf("\n");
SLTDestroy(&s);
}
void test3()
{
SListNode* s = NULL;//先初始化
SListPushFront(&s, 11);
SListPushFront(&s, 7);
SListPushFront(&s, 10);
SListPushBack(&s, 8);
SListPushBack(&s, 88);
SListPushBack(&s, 888);
SListPushBack(&s, 82);
SListPushBack(&s, 98);
SListPopBack(&s);
SListPopFront(&s);
SListPrint(s);//注意传参
printf("\n");
SListNode* pos = SListFind(s, 888);
SLTInsert(&s, pos, 666);
SListPrint(s);
SListEraseAfter(pos);
SListPrint(s);
SListInsertAfter(pos, 777);
SListPrint(s);
SLTDestroy(&s);
}
int main()
{
//test1();
//test2();
test3();
return 0;
}