链表分类
链表分为单向链表(Singly linked lis)、双向链表(Doubly linked list)、循环链表(Circular Linked list)。
应用: 1).用于数据数目事先无法确定的情况;
2).用于数据数在内存中不连续存放的情况;
组成: 1). 头指针
2). 结点(节点)
2.1 数据域
2.2 指针域(指向下一个节点)
2.链表操作:
2.1 链表创建:
步骤:1.创建一个结点(申请可以存放一个结点数据的内存空间)
2.填充结点数据(实际数据,指针)
3.返回头结点首地址
3 链表插入:
步骤:1.创建一个结点(申请可以存放一个结点数据的内存空间)
2.填充结点数据(实际数据,指针)
3.根据插入算法,将结点链接到链表中。
4 链表删除
单向链表(Singly linked lis)
单向链表是最简单的链表形式。我们将链表中最基本的数据称为节点(node),每一个节点包含了数据块和指向下一个节点的指针。
#ifndef __LIST_H__
#define __LIST_H__
typedef int DATA;
typedef struct node
{
DATA data;
struct node* next;
}Node;
Node* list_create(DATA);
Node* list_addhead(Node*,DATA);
Node* list_addtail(Node*,DATA);
Node* list_addtail_v2(Node*,DATA);
Node* list_delete(Node*,DATA);
void list_show(Node*);
void list_free(Node**);
#endif
#include "list.h"
#include <stdlib.h>
#include <stdio.h>
Node* list_create(DATA data)
{
Node* p = (Node*)malloc(sizeof(Node));
if(!p)
{
puts("申请内存失败!");
return NULL;
}
p->data = data;
p->next = NULL;
return p;
}
Node* list_addhead(Node* head,DATA data)
{
if(!head)
{
return list_create(data);
}
Node* p = (Node*)malloc(sizeof(Node));
if(!p)
{
puts("申请内存失败!");
return NULL;
}
p->data = data;
p->next = head;
head = p;
return head;
}
Node* list_addtail(Node* head,DATA data)
{
if(!head)
return list_create(data);
Node* p = (Node*)malloc(sizeof(Node));
if(!p)
{
puts("申请内存失败!");
return head;
}
p -> data = data;
p -> next = NULL;
Node* q = head;
while(q->next)
{
q = q->next;
}
q ->next = p;
return head;
}
Node* list_addtail_v2(Node* head,DATA data)
{
Node* pNew = (Node*)malloc(sizeof(Node));
if(!pNew)
{
puts("申请内存失败!");
return head;
}
pNew -> data = data;
pNew -> next = NULL;
Node* p = head,*q = NULL;
while(p)
{
q = p;
p = p ->next;
}
if(head)
q->next = pNew;
else
head = pNew;
return head;
}
Node* list_delete(Node* head,DATA del)
{
if(!head)
{
puts("链表为空!!!");
return NULL;
}
Node* p = head;
if(head -> data == del)
{
head = head->next;
free(p);
return head;
}
Node* q = NULL;
while(p)
{
if(p -> data == del)
{
q->next = p ->next;
free(p);
return head;
}
q = p;
p = p->next;
}
puts("删除的数据不存在!");
return head;
}
void list_show(Node* head)
{
Node* p = head;
while(p)
{
printf("%5d",p->data);
p = p->next;
}
printf("\n");
}
void list_free(Node** head)
{
Node *p = *head,*q;
while(p)
{
q = p;
p = p->next;
free(q);
}
*head = NULL;
}
#include "list.h"
#include <stdio.h>
int main(void)
{
int del;
int a[] = {1,3,5,7,9};
Node* head = NULL;
head = list_delete(head,7);
register int i = 0;
for(; i< sizeof a /sizeof a[0]; i++)
{
head = list_addtail_v2(head,a[i]);
}
list_show(head);
puts("=============");
while(1)
{
puts("请输入要删除的数据:");
scanf("%d",&del);
if(del == -1)
break;
head = list_delete(head,del);
list_show(head);
}
list_free(&head);
list_show(head);
return 0;
}
双向链表(Doubly linked list)
顾名思义,双向链表就是有两个方向的链表。同单向链表不同,在双向链表中每一个节点不仅存储指向下一个节点的指针,而且存储指向前一个节点的指针。通过这种方式,能够通过在O(1)时间内通过目的节点直接找到前驱节点,但是同时会增加大量的指针存储空间。
#ifndef __DLIST_H__
#define __DLIST_H__
typedef int DATA;
typedef struct _node
{
DATA data;
struct _node *prev;
struct _node *next;
}Node;
int Dlist_create(Node** head,DATA data);
int Dlist_addhead(Node** head,DATA data);
int Dlist_addtail(Node** head,DATA data);
int Dlist_insert_bypos(Node** head,Node* pos,DATA data);
int Dlist_insert(Node** head,DATA data1,DATA data);
Node* Dlist_find(Node*,DATA);
int Dlist_delete_bypos(Node** head,Node* pos);
int Dlist_delete(Node** head,DATA data);
void Dlist_show(Node*);
void Dlist_free(Node** head);
#endif
#include "Dlist.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/**
* @brief 创建双向链表
* @param head: 头指针地址
* @param data: 节点数据
* @retval 成功返回0,失败返回-1
*/
int Dlist_create(Node** head,DATA data)
{
Node* p = (Node*)malloc(sizeof(Node));
if(!p)
{
puts("创建结点失败!");
return -1;
}
p -> data = data;
p -> next = NULL;
p -> prev = NULL;
*head = p;
return 0;
}
int Dlist_addhead(Node** head,DATA data)
{
Node* p = (void*)malloc(sizeof(Node));
if(!p)
{
puts("创建结点失败\n");
return -1;
}
p -> data = data;
p -> prev = NULL;
p -> next = *head;
if(*head)
(*head)->prev = p;
*head = p;
return 0;
}
int Dlist_addtail(Node** head,DATA data)
{
Node* p = *head,*q = NULL;
Node* pNew = (void*)malloc(sizeof(Node));
if(!pNew)
{
puts("创建结点失败\n");
return -1;
}
pNew -> data = data;
pNew -> next = NULL;
while(p)
{
q = p;
p = p -> next;
}
pNew -> prev = q;
if(*head)
q -> next = pNew;
else
*head = pNew;
return 0;
}
Node* Dlist_find(Node* head,DATA data)
{
Node* p = head;
while(p)
{
if(p -> data == data)
return p;
p = p -> next;
}
return NULL;
}
int Dlist_insert_bypos(Node** head,Node* pos,DATA data)
{
if(*head == NULL)
return Dlist_create(head,data);
if(*head == pos)
return Dlist_addhead(head,data);
if(!pos)
return Dlist_addtail(head,data);
Node* p = (Node*)malloc(sizeof(Node));
if(!p)
{
puts("创建结点失败!");
return -1;
}
p -> data = data;
p -> prev = pos -> prev;
p -> next = pos;
pos -> prev -> next = p;
pos -> prev = p;
return 0;
}
int Dlist_insert(Node** head,DATA data1,DATA data2)
{
Node* pos = Dlist_find(*head,data1);
return Dlist_insert_bypos(head,pos,data2);
}
int Dlist_delete_bypos(Node** head,Node* pos)
{
if((*head == NULL) || !pos)
{
puts("链表为空,或位置不存在!");
return -1;
}
if((pos->prev == NULL) &&(pos->next == NULL))
{
*head = NULL;
free(pos);
return 0;
}
if(pos == *head)
{
pos->next->prev = NULL;
*head = pos->next;
free(pos);
return 0;
}
if(pos -> next == NULL)
{
pos -> prev ->next = NULL;
free(pos);
return 0;
}
pos->prev->next = pos -> next;
pos->next->prev = pos -> prev;
free(pos);
return 0;
}
int Dlist_delete(Node** head,DATA data)
{
Node* pos = Dlist_find(*head,data);
return Dlist_delete_bypos(head,pos);
}
void Dlist_show(Node* head)
{
Node* p = head;
while(p)
{
printf("%6d",p->data);
p = p -> next;
}
printf("\n");
}
void Dlist_free(Node** head)
{
Node* p = *head,*q = NULL;
while(p)
{
q = p;
p = p -> next;
free(q);
}
*head = NULL;
}
#include "Dlist.h"
#include <stdio.h>
int main(void)
{
int del;
int a[] = {1,3,5,7,9};
Node* head = NULL;
register int i = 0;
for(; i< sizeof a /sizeof a[0]; i++)
{
if(Dlist_addtail(&head,a[i]) == -1)
{
printf("插入数据 %d 失败!\n",a[i]);
}
}
Dlist_show(head);
puts("=============");
while(1)
{
puts("请输入要[查找/删除]的数据:");
scanf("%d",&del);
if(del == -1)
break;
//Node* pos = Dlist_find(head,del);
//Dlist_insert(&head,pos,100);
if(Dlist_insert(&head,del,888)== -1)
{
puts("删除失败!");
continue;
}
Dlist_show(head);
}
Dlist_free(&head);
//list_show(head);
return 0;
}
循环链表(Circular Linked list)
循环链表与双向链表相似,不同的地方在于:在链表的尾部增加一个指向头结点的指针,头结点也增加一个指向尾节点的指针,以及第一个节点指向头节点的指针,从而更方便索引链表元素。
#ifndef __DLIST_H__
#define __DLIST_H__
typedef int DATA;
typedef struct _node
{
DATA data;
struct _node *prev;
struct _node *next;
}Node;
Node* list_init(DATA data);
void list_add_head(Node *new, Node *head);
void list_add_tail(Node *new, Node *head);
void list_show(Node*);
//void list_free(Node** head);
#endif
#include "dclist.h"
#include <stdio.h>
#include <stdlib.h>
Node* list_init(DATA data)
{
Node* p = (Node*)malloc(sizeof(Node));
if(!p)
return NULL;
p -> data = data;
p -> prev = p;
p -> next = p;
return p;
}
static void __list_add(Node *new,Node *prev,Node *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
void list_add_head(Node *new, Node *head)
{
__list_add(new, head, head->next);
}
void list_add_tail(Node *new, Node *head)
{
__list_add(new, head->prev, head);
}
void list_show(Node* head)
{
Node* p = head;
while(p)
{
printf("%6d",p->data);
p = p ->next;
if(p == head)
break;
}
printf("\n");
}
#include "dclist.h"
#include <stdio.h>
int main(void)
{
int del;
int a[] = {1,3,5,7,9};
Node* head = list_init(a[0]);
register int i = 1;
for(; i< sizeof a /sizeof a[0]; i++)
{
Node* new = list_init(a[i]);
list_add_tail(new,head);
}
list_show(head);
puts("=============");
/*
while(1)
{
puts("请输入要[查找/删除]的数据:");
scanf("%d",&del);
if(del == -1)
break;
//Node* pos = Dlist_find(head,del);
//Dlist_insert(&head,pos,100);
if(Dlist_insert(&head,del,888)== -1)
{
puts("删除失败!");
continue;
}
Dlist_show(head);
}
Dlist_free(&head);
*/
//list_show(head);
return 0;
}