数组和链表的区别
数组
一次性分配一块连续的存储区域
- 优点:随机访问元素效率高
- 缺点:
-
- 需要分配一块连续的存储区域(很大区域,有可能分配失败)
-
- 删除和插入某个元素效率低
链表
无需一次性分配一块连续的存储区域,只需分配n块节点存储区域,通过指针建立关系
- 优点:
-
- 不需要一块连续的存储区域
-
- 删除和插入某个元素效率高
- 缺点:随机访问元素效率低
链表
链表是由一系列节点组成,每个节点包含两个域
- 一个是数据域,数据域用来保存用户数据
- 另外一个是指针域,保存下一个节点的地址
链表在内存是非连续的
-
链表在指定位置插入和制除不需要移动元素,只需要修改指针即可
-
查找效率低一些相对于数组
-
链表相对于数组来讲,多了指针域空间开销
-
拿到链表的第一个节点,就相当于拿到整个链表
-
头节点不保存任何数据
链表的分类
- 静态链表 动态列表
- 单向链表 双向链表 循环链表 单向循环链表 双向循环链表
静态链表
所有结点都是在程序中定义的,不是临时开辟的,也不能用完后释放 ,这种链表称为”静态链表”
#include <stdio.h>
//链表结点类型定义
struct LinkNode {
int data;
struct LinkNode *next;
};
void test() {
struct LinkNode node1 = { 10,NULL };
struct LinkNode node2 = { 20,NULL };
struct LinkNode node3 = { 30,NULL };
struct LinkNode node4 = { 40,NULL };
struct LinkNode node5 = { 50,NULL };
struct LinkNode node6 = { 60,NULL };
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
node4.next = &node5;
node5.next = &node6;
//如何遍历链表
//先定义一个辅助指针变量
struct LinkNode* pCurrent = &node1;
while (pCurrent != NULL) {
printf("%d ", pCurrent->data);
//指针移动到下一个元素的首地址
pCurrent = pCurrent->next;
}
}
int main() {
test(); //10 20 30 40 50 60
return 0;
}
动态列表
所谓动态链表,是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。
LinkList.h
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#pragma once
#ifdef __cplusplus
extern "C"{
#endif
//定义节点数据类型
struct LinkNode
{
int data;
struct LinkNode *next;
};
//初始化链表
struct LinkNode* Init_LinkList();
//在值为o1dva1的前面插入一个新的数据newval
void InsertByValue_LinkList(struct LinkNode* header, int oldval, int newval);
//删除值为val的结点
void RemoveByValue_LinkList(struct LinkNode* header, int delValue);
//遍历
void Foreach_LinkList(struct LinkNode* header);
//销毁链表
void Destroy_LinkList(struct LinkNode* header);
//清空链表
void Clear_LinkList(struct LinkNode* header);
#ifdef __cplusplus
}
#endif
LinkList.c
#include"LinkList.h"
//初始化链表
struct LinkNode* Init_LinkList()
{
//创建头节点
struct LinkNode* header = malloc(sizeof(struct LinkNode));
header->data = -1;
header->next = NULL;
//尾部指针
struct LinkNode* pRear = header;
int val = -1;
while (true)
{
printf("输入插入的数据(输入-1结束):\n");
scanf("%d", &val);
if (val == -1)
{
break;
}
//先创建新结点
struct LinkNode* newnode = malloc(sizeof(struct LinkNode));
newnode->data = val;
newnode->next = NULL;
//更新尾部指针指向
pRear->next = newnode;
pRear = newnode;
}
return header;
}
//在值为o1dva1的前面插入一个新的数据newval
void InsertByValue_LinkList(struct LinkNode* header, int oldval, int newval)
{
if (NULL == header)
{
return;
}
//两个辅助指针变量
struct LinkNode* pPrev = header;
struct LinkNode* pCurrent = header->next;
while (pCurrent != NULL)
{
if (pCurrent->data == oldval)
{
break;
}
pPrev = pCurrent;
pCurrent = pCurrent->next;
}
//如果pCurrent为NULL,说明链表中不存在值为oldva1的结点
if (pCurrent == NULL)
{
return;
}
//先创建新结点
struct LinkNode* newnode = malloc(sizeof(struct LinkNode));
newnode->data = newval;
newnode->next = NULL;
//新结点插入到链表中
newnode->next = pCurrent;
pPrev->next = newnode;
}
//删除值为val的结点
void RemoveByValue_LinkList(struct LinkNode* header, int delValue)
{
if (NULL == header)
{
return;
}
//两个辅助指针变量
struct LinkNode* pPrev = header;
struct LinkNode* pCurrent = pPrev->next;
while (pCurrent != NULL)
{
if (pCurrent->data == delValue)
{
break;
}
//移动两个辅助指针
pPrev = pCurrent;
pCurrent = pCurrent->next;
}
if (pCurrent == NULL)
{
return;
}
//重新建立待删除节点的前驱和后继结点关系
pPrev->next = pCurrent->next;
//释放删除节点内存
free(pCurrent);
pCurrent = NULL;
}
//遍历
void Foreach_LinkList(struct LinkNode* header)
{
if(NULL == header)
{
return;
}
//辅助指针变量
struct LinkNode* pCurrent = header->next;
while (pCurrent != NULL)
{
printf("%d ", pCurrent->data);
pCurrent = pCurrent->next;
}
printf("\n");
}
//销毁链表
void Destroy_LinkList(struct LinkNode* header)
{
if (NULL == header)
{
return;
}
//辅助指针变量
struct LinkNode* pCurrent = header;
while (pCurrent != NULL)
{
//先保存下当前结点的下一个节点地址
struct LinkNode* pNext = pCurrent->next;
//释放当前结点内存
printf("%d节点被销毁!\n", pCurrent->data);
free(pCurrent);
//指针向后移动
pCurrent = pNext;
}
}
//清空链表
void Clear_LinkList(struct LinkNode* header)
{
if (NULL == header)
{
return;
}
//辅助指针变量
struct LinkNode* pCurrent = header->next;
while (pCurrent != NULL)
{
//先保存下当前结点的下一个节点地址
struct LinkNode* pNext = pCurrent->next;
//释放当前结点内存
free(pCurrent);
//pCurrent指向下一个节点
pCurrent = pNext;
}
header->next = NULL;
}
TestLinkList.c
#include"LinkList.h"
void test()
{
//初始化链表 100 200 300 400 500 600
struct LinkNode *header = Init_LinkList();
//打印链表
Foreach_LinkList(header);
//插入数据 100 200 666 300 400 500 600
InsertByValue_LinkList(header, 300, 666);
//打印链表
printf("--------------------------------\n");
Foreach_LinkList(header);
//删除元素 666
RemoveByValue_LinkList(header, 666);
//打印链表
printf("--------------------------------\n");
Foreach_LinkList(header);
//清空
Clear_LinkList(header);
//打印链表
printf("--------------------------------\n");
Foreach_LinkList(header);
//销毁
Destroy_LinkList(header);
}
int main() {
test();
return 0;
}