1.单链表
建立单链表:
(1)创建节点:
struct node*create_node()
{
struct node *pnew = NULL;
pnew = (struct node*)malloc(sizeof(struct node));
if(pnew==NULL)
{
printf("malloc error!\n");
exit(-1);
}
pnew->next = NULL;
return pnew;
}
(2)头插法: 将新节点从头插入链表
//头插法创建链表
struct node*create_list_by_head()
{
struct node *head = NULL, *pnew = NULL;
int x;
scanf("%d", &x);
while(getchar()!='\n');
while(x)
{
//1、创建新的节点,并且赋值
pnew = (struct node*)malloc(sizeof(struct node));
if(NULL == pnew)
{
printf("malloc error!%s, %d\n", __FILE__, __LINE__ );
exit(-1);
}
pnew->data = x;
pnew->next = NULL;
//2、加入链表
pnew->next = head;
head = pnew;
scanf("%d", &x);
while(getchar()!='\n');
}
return head;
}
尾插法: 将新节点从尾部插入链表
//尾插法创建链表
struct node *create_list_by_tail()
{
struct node* head = NULL; //头指针, 保存第一个节点的地址
struct node* pnew = NULL; //保存新的节点地址
struct node* tail = NULL; //保存最后一个节点的地址
int x;
scanf("%d", &x);
while(getchar()!='\n');
while(x)
{
//1、创建新的节点, 并初始化每一个成员
pnew = (struct node*)malloc(sizeof(struct node));
if(NULL == pnew)
{
printf("malloc error!%s, %d\n", __FILE__, __LINE__ );
exit(-1);
}
pnew->data = x;
pnew->next = NULL;
//2、加入链表
if(NULL == head) //空链表
{
head = pnew;
tail = pnew;
}
else // 非空链表
{
tail->next = pnew;
tail = pnew;
}
scanf("%d", &x);
while(getchar()!='\n');
}
return head;
}
(3)遍历链表:声明一个指针p,从头结点指向的第一个结点开始,如果p不为空,那么就输出当前结点的值,并将p指向下一个结点,直到遍历到最后一个结点为止。
//遍历链表
void show_list(struct node *head)
{
if(NULL == head)
{
printf("空链表!\n");
}
else
{
struct node *p = head;
while(p != NULL)
{
printf("[%d|%p]-->", p->data, p->next);
p = p->next;
}
printf("\n");
}
return ;
}
(4)删除链表:先检查删除位置的合法性,然后从头开始遍历,找到表中的第 i-1 个结点,即被删除结点的前驱结点*psearch,被删除结点为*pdel,修改*pdel的指针域,将其指向*psearch的下一个结点,最后再释放结点*pdel的存储空间。
struct node*list_del_by_index(struct node *head, int index)
{
//入参检查
if(head == NULL)
{
return head;
}
int len = list_len(head);
if(index<1 || index>len)
{
return head;
}
//正确流程
//删除操作的步骤:
//(1) 保存删除节点的地址
//(2) 将节点从链表中移除
//(3) 释放内存
struct node *pdel = NULL;
if(1 == index) //头删
{
pdel = head;
head = head->next;
}
else //中间删除或者 尾部删除
{
//查找删除节点
pdel = list_search_by_index(head, index);
//查找删除节点的前一个节点
struct node *psearch = list_search_by_index(head, index-1);
psearch->next = pdel->next;
}
free(pdel);
return head;
}
(5)插入新节点:从表头开始遍历,查找第 i-1个结点,即插入位置的前驱结点为psearch,然后令新结点pnew的指针域指向pnew的后继结点,再令结点psearch的指针域指向新结点*pnew。
struct node*list_insert_by_index(struct node *head, int index, int data)
{
//入参检查
int len = list_len(head);
#if 0
if(index<1 || index>len+1)
{
printf("param error!\n");
return head;
}
#endif
if(index < 1)
{
index = 1;
}
if(index > len+1)
{
index = len+1;
}
//正确的流程
struct node *pnew = create_node();
pnew->data = data;
if(index == 1)
{
pnew->next = head;
head = pnew;
}
else //中间 或者 尾部追加
{
//查找index节点的前一个节点
struct node *psearch = NULL;
psearch = list_search_by_index(head, index-1);
//将新的节点加入链表
pnew->next = psearch->next;
psearch->next = pnew;
}
return head;
}
(6)查找链表节点:从单链表的第一个结点开始,顺着指针域逐个往下搜索,直到找到第 i 个结点为止,否则返回最后一个结点的指针域NULL
struct node *list_search_by_index(struct node *head, int index)
{
//入参检查
if(NULL == head)
{
return NULL;
}
int len = list_len(head);
if(index<1 || index>len)
{
printf("param error!%s, %d\n", __FILE__,__LINE__);
return NULL;
}
//正确流程
struct node *p = head;
for(int i=1; i<index; i ++)
{
p = p->next;
}
return p;
}
2.双向链表
可以从头遍历到尾,也可以从尾遍历到头
每次在插入或删除某个节点时, 需要处理四个节点的引用