开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
数据结构
第二章
第三节 链表
以链式存储的方式称为链表
每个链表节点除了存放数据元素(数据域)之外,还存储下一个节点的地址(地址域)
单链表
特点
不需要一块连续的空间,每个节点可单独占据一块小的空间,然后每个节点通过保存下一个节点的地址来保证连续,但是单链表不具有随机存取的特点,随机存储即存储器中数据的读取与写入的时间和这个信息所在的位置无关。
定义一个单链表
typedef struct LNode{//typedef 定义别名
int data;
struct LNode *node;
}LNode,*LNodeList;
LNode L;
初始化单链表
LNode* create(int length){
int i;
LNode *p,*header;
header=p=(LNode *)malloc(sizeof(LNode));//创建一个头节点
header->data=1;
for(i=0;i<length;i++){
LNode *lnode=(LNode *)malloc(sizeof(LNode));
lnode->data=i;
lnode->node=NULL;
p->node=lnode;
p=lnode;
}
return p;
}
单链表操作——删除、清空
单链表操作——表长、查找
表长
取第i个元素
按值查找
单链表基本操作的时间复杂度
循环链表
循环链表:每个节点包括一个后继节点,然后链表尾部指向头部。
循环链表头部和尾部所花费的时间复杂度
创建循环链表
LNode* create1(int length){
int i;
LNode *p,*header;
header=p=(LNode *)malloc(sizeof(LNode));//创建一个头节点
header->data=1;
for(i=0;i<length;i++){
LNode *lnode=(LNode *)malloc(sizeof(LNode));
lnode->data=i+1;
lnode->node=NULL;
p->node=lnode;
p=lnode;
}
p->node=header; //尾部指向头部
return p;
}
尾插法合并两个循环链表
void lastInsert(LNode* list,LNode* list1){
int i=0;
LNode *p,*o;
p=list->node;
list->node=list1->node->node;
list1->node=p;
while(i!=10){
p=p->node;
printf("打印结果:%d\n",p->data);
i++;
}
}
双向链表
特点
与单链表相比,双向链表多了前驱节点,单链表查询后继节点的时间复杂度为O(1), 查询前驱节点的时间复杂度为O(n),因为单链表没有前驱节点的地址域。而双向链表有一个前驱节点和后继节点的地址域,因此查询前驱和后继节点的时间复杂度都是O(1)。 定义双向链表
typedef struct LNode{
int data;
struct LNode *pre;//前驱节点
struct LNode *next;//后继节点
}LNode,*LNodeList;
创建双向链表
//创建双向链表
void create(int length){
LNode *p,*q;
int i;
p=q=(LNode *)malloc(sizeof(LNode));
q->data=10;
for(i=0;i<length;i++){
LNode *l=(LNode *)malloc(sizeof(LNode));
l->data=i;
p->next=l;
l->pre=p;
p=p->next;
}
while(p!=q){
printf("输出值:%d==========%d\n",p->pre->data,p->data);
p=p->pre;
}
}