数据结构----线性表之链式存储
以下内容只是学习记录:
一、链式存储定义
用一组任意存储位置存储数据元素,存储位置可以连续也可以不连续,存储格式如下图:
由结构图可以看出链式存储相比于顺序存储
优点:
1、插入删除灵活,只需修改指针即可
2、内存动态分配,无需像顺序表那样存储空间不够需要额外写代码动态增加存储空间
缺点: 1、存储密度小,即存储空间利用率低
2、查找数据没有顺序表方便,顺序表可以通过下标直接计算存储地址,而单链式结构查找数据需要从表头开始一个一个查找
二、链式存储实现
单链表代码实现:
1、创建单链表结构体
#define ElemType int typedef struct ListNode { ElemType data;//数据域 struct ListNode *next;//指向下一个节点的指针 }ListNode; typedef ListNode* List;//给ListNode*重新起个名字 ,关于结构体的定义以及使用,请参考博客:
2、定义一个单链表并初始化为NULL
void InitList(List *head)
{
(*head) = NULL;
}
void main()
{
List mylist ;//List表示类型为ListNode结构体的指针变量
InitList(&mylist);//这里必须要传入mylist的地址,否则就是拷贝传递,最终返回时,mylist还是没有改变
printf("%p",mylist);
}
代码解析:
3、创建链表并赋值
(1) 头插法
下图为头插法示意图,即在头节点和链表之间插入一个节点
代码如下:
void HeadCreatList(List *head) { for (int i = 1; i < 10; i++) { ListNode *s = (ListNode *)malloc(sizeof(ListNode)); assert(s != NULL); s->data = i; s->next = (*head)->next; (*head)->next = s; } }
注:使用头节点的好处:
1、火车跑得快全靠火车头,链表要安全全靠头节点,可以保护头节点不变
2、代码实现较简单。不信?你可以自己动手写一个不带头节点的链表实现,对比一下!
3、可以用头节点数据区存储链表的额外信息,比如链表的长度等,这样计算链表长度直接查询头节点即可获得
使用头节点的好处:
占用空间增大,但我认为这点头节点占据的存储空间相比较它带来的好处可忽略
(2) 尾插法
下图是尾插法示意图
代码如下:
void TailCreatList(List *head) { ListNode *p = *head; for (int i = 1; i < 10; i++) { p = p->next = (ListNode *)malloc(sizeof(ListNode)); assert(p != NULL); p->data = i; p->next = NULL; } }
(3)显示链表
void ShowList(List head) { ListNode *p = head->next;//head指向的下一个节点数据才是真正的数据开始 while (p != NULL) { printf("%d-->", p->data); p = p->next; } printf("Nul.\n"); }