封装链表
尾添加的效率低,非法下标的判断效率也很低
1、单链表
节点:
数据域
指针域
数据项:
头指针
尾指针
节点数量
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define TYPE int
// 单链表的实现
// 设计节点
typedef struct Node
{
TYPE data;
struct Node* next;
}Node;
Node* create_node(TYPE data)
{
Node* node = malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
// 设计单链表结构
typedef struct List
{
Node* head; // 头指针
Node* tail; // 尾指针
size_t size; // 数量
}List;
// 创建带头节点单链表
List* create_list(void)
{
List* list = malloc(sizeof(List));
list->head = create_node(0); // 创建一头节点,这是一个带头节点的链表,节点的数据没有意义
list->tail = NULL;
return list;
}
// 头添加
void add_head_list(List* list,TYPE data)
{
Node* node = create_node(data);
if(list->size == 0)
{
list->head->next = node;
list->tail = node;
}
else
{
node->next = list->head->next;
list->head->next = node;
}
list->size++;
}
// 尾添加
void add_tail_list(List* list,TYPE data)
{
Node* node = create_node(data);
if(list->size ==0)
{
list->head->next = node;
list->tail = node;
}
else
{
list->tail->next = node;
list->tail = node;
}
list->size++;
}
// 头删除
bool del_head_list(List* list)
{
if(list->size == 0) return false;
Node* tmp = list->head->next;
list->head->next = tmp->next; //list->head->next->next
if(1 == list->size) list->tail = NULL;
free(tmp);
list->size--;
return true;
}
// 尾删除
bool del_tail_list(List* list)
{
if(0 == list->size) return false;
free(list->tail);
if(1 == list->size)
{
list->head->next = NULL;
list->tail = NULL;
}
else
{
Node* n = list->head->next;
while(n->next != list->tail) n = n->next;
n->next = NULL;
list->tail = n;
}
list->size--;
return true;
}
// 插入
bool insert_list(List* list,int index,TYPE data)
{
if(index < 0 || list->size <= index) return false;
Node* node = create_node(data);
Node* prev = list->head; // 待插入位置的上一个位置
for(int i=0;i<index;i++)
{
prev = prev->next;
}
node->next = prev->next;
prev->next = node;
list->size;
return true;
}
// 按值删除
bool del_value_list(List* list,TYPE data)
{
if(data == list->tail->data) return del_tail_list(list);
if(data == list->head->next->data) return del_head_list(list);
for(Node* n=list->head->next;n->next->next != NULL;n=n->next)
{
if(data == n->next->data)
{
Node* tmp = n->next;
n->next = tmp->next;
free(tmp);
list->size--;
return true;
}
}
return false;
}
// 按位置删除
bool del_index_list(List* list,int index)
{
if(0>index || index >= list->size) return false;
if(index == 0) return del_head_list(list);
if(index == list->size-1) return del_tail_list(list);
Node* prev = list->head->next;
for(int i=1;i<index;i++)
{
prev = prev->next;
}
Node* tmp = prev->next;
prev->next = tmp->next;
free(tmp);
list->size--;
return true;
}
// 值修改 全部值
bool modify_value_list(List* list,TYPE old,TYPE data)
{
bool flag = false;
Node* n = list->head->next;
for(int i=0;i<list->size;i++)
{
if(n->data == old)
{
n->data = data;
flag = true;
}
n=n->next;
}
return flag;
}
// 位置修改
bool modify_index_list(List* list,int index,TYPE val)
{
if(0>index || index >= list->size) return false;
Node* n = list->head->next;
for(int i=0;i<index;i++)
{
n = n->next;
}
n->data = val;
return true;
}
// 查询
int query_list(List* list,TYPE data)
{
Node* n = list->head->next;
for(int i =0;n;n=n->next,i++)
{
if(data == n->data) return i;
}
return -1;
}
// 排序
void sort_list(List* list)
{
for(Node* i=list->head->next;i->next != NULL;i=i->next)
{
for(Node* j=i->next;j != NULL;j=j->next)
{
if(i->data > j->data)
{
TYPE tmp = i->data;
i->data = j->data;
j->data = tmp;
}
}
}
}
// 访问
bool access_list(List* list,int index,TYPE* val)
{
if(0>index || index>=list->size) return false;
Node* n = list->head->next;
while(index--) n=n->next;
/*
for(int i=0;i<index;i++)
{
n=n->next;
}
*/
*val = n->data;
return true;
}
// 清空
void clean_list(List* list)
{
while(list->tail) del_tail_list(list);
}
// 销毁
void destory_list(List* list)
{
clean_list(list);
free(head);
//frea(tail); 可但是没必要,因为tail本来就是指向空的
free(list);
}
// 遍历
void show_list(List* list)
{
for(Node* n = list->head->next;n;n=n->next)
{
printf("%d ",n->data);
}
printf("\n");
}
int main(int argc,const char* argv[])
{
List* list = create_list();
for(int i=0;i<10;i++)
{
add_tail_list(list,i);
}
show_list(list);
/*
for(int i=0;i<5;i++)
{
del_tail_list(list);
}
*/
//insert_list(list,4,59); //插入和添加的区别,插入不能在最后的位置插入,最后的位置要增加数据叫做添加
//del_value_list(list,0);
//del_index_list(list,7);
modify_index_list(list,3,59);
//show_list(list);
//modify_value_list(list,59,60);
//sort_list(list);
show_list(list);
//printf("index:%d\n",query_list(list,7));
int num=-1;
access_list(list,3,&num);
printf("num:%d\n",num);
return 0;
}
2、静态链表
节点:
数据域
游标
#include <stdio.h>
typedef struct Node
{
int data;
int i; //游标
}Node;
Node list[100];
int main()
{
Node* head = list[0];
head->i = 5;
list[5].i = 7;
list[3].i = 3;
}
静态链表的节点储存在连续的内存,通过游标来访问下一个节点
原因:其他的高级语言没有指针
这种链表的插入删除时只能通过修改游标的值,而不用申请、释放内存来达到链式结构的效果
牺牲了随机访问的功能,是一种给没有指针的编译实现单链表
3、循环链表
链表的最后一个节点的next不再指向NULL,而是指向头节点,这种链表叫做单项循环链表,简称循环链表,它的好处是可以通过任意节点遍历整个链表
4、双向链表
节点:
前驱指针
数据域
后继指针
数据项:
头节点
节点数量
双向循环链表的特点:
1、从任何节点都可以遍历整个链表
2、已知节点的位置,可以选择从前到后,还是从后到前进行遍历,依次提高链表的访问效率
未封装
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define TYPE int
// -----带头节点的双向循环链表----
// 设计双向节点
typedef struct Node
{
struct Node* prev; //前驱指针
TYPE data; //数据域
struct Node* next; //后缀指针
}Node;
// 创建节点
Node* create_node(TYPE data)
{
Node* node = malloc(sizeof(Node));
node->prev = node;
node->data = data;
node->next = node;
return node;
}
// 添加函数
void _add_list(Node* p,Node* n,TYPE data)
{
Node* node = create_node(data);
node->next = n;
node->prev = p;
p->next = node;
n->prev = node;
}
// 删除函数
void _del_list(Node* node)
{
node->prev->next = node->next; // node 是当前节点
node->next->prev = node->prev;
free(node);
}
// (带头节点) 头添加
void add_head_list(Node* head,TYPE data)
{
_add_list(head,head->next,data);
}
// 尾添加
void add_tail_list(Node* head,TYPE data)
{
_add_list(head->prev,head,data);
}
// 插入
bool insert_list(Node* head,size_t index,TYPE data)
{
Node* n = head->next;
for(int i=0;i<index;i++)
{
n = n->next;
if(head == n) return false;
}
// n是待插入的位置
_add_list(n->prev,n,data);
return true;
}
// 按位置删除
bool del_index_list(Node* head ,size_t index)
{
Node* n = head->next;
for(int i=0;i<index;i++)
{
n=n->next;
if(n == head) return false;
}
_del_list(n);
return true;
}
// 按值删除
bool del_value_list(Node* head,TYPE data)
{
bool flag = false;
for(Node* n=head->next; n != head ;n=n->next)
{
if(n->data == data)
{
_del_list(n);
flag = true;
}
}
return flag;
}
// 遍历
void show_list(Node* head)
{
for(Node* n=head->next;head != n;n=n->next)
{
printf("%d ",n->data);
}
printf("\n");
}
int main(int argc,const char* argv[])
{
Node* head = create_node(0);
for(int i=0;i<10;i++)
{
add_tail_list(head,i);
}
show_list(head);
insert_list(head,5,98);
del_index_list(head,4);
show_list(head);
del_value_list(head,7);
show_list(head);
return 0;
}
封装后
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define TYPE int
// 设计节点
typedef struct Node
{
struct Node* prev; //前驱指针
TYPE data; //数据域
struct Node* next; //后缀指针
}Node;
// 创建节点
Node* create_node(TYPE data)
{
Node* node = malloc(sizeof(Node));
node->prev = node;
node->data = data;
node->next = node;
return node;
}
// 设计双向链表结构
typedef struct DoubleList
{
Node* head; // 头
size_t size; // 数量
}DoubleList;
// 创建链表结构
DoubleList* creat_list(void)
{
DoubleList* list = malloc(sizeof(DoubleList));
list->head = create_node(0);
list->size = 0;
return list;
}
// 在前驱和后继之间添加一个节点
// 下划线开头的函数,是其他函数的依赖函数
void _add_list(Node* p,Node* n,TYPE data)
{
Node* node = create_node(data);
node->prev = p;
node->next = n;
p->next = node;
n->prev = node;
}
// 删除当前节点
void _del_list(Node* node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
free(node);
}
// 访问指定位置的节点
Node* _index_list(DoubleList* list,size_t index)
{
if(0>index || index>=list->size) return NULL;
if(index< list->size/2)
{
// 从前往后找
Node* n = list->head->next;
while(index--) n = n->next;
return n;
}
else
{
Node* n = list->head->prev;
while(++index <list->size) n = n->prev;
return n;
}
}
// 访问指定数值的节点
Node* _value_list(DoubleList* list,TYPE data)
{
for(Node* n=list->head->next;n!=list->head;n=n->next)
{
if(n->data == data) return n;
}
return NULL;
}
// 头添加
void add_head_list(DoubleList* list,TYPE data)
{
_add_list(list->head,list->head->next,data);
list->size++;
}
// 尾添加
void add_tail_list(DoubleList* list,TYPE data)
{
_add_list(list->head->prev,list->head,data);
list->size++;
}
// 插入
bool insert_list(DoubleList* list,size_t index,TYPE data)
{
Node* n = _index_list(list,index);
if(n == NULL) return false;
_add_list(n->prev,n,data);
list->size++;
}
// 按位置修改
bool modify_index_list(DoubleList* list,size_t index,TYPE data)
{
Node* n = _index_list(list,index);
if(n == NULL) return false;
n->data = data;
return true;
}
// 按值修改(全部)
int modify_value_list(DoubleList* list,TYPE old,TYPE data)
{
bool flag = false;
int cnt = 0;
for(Node* n=list->head->next;n!=list->head;n=n->next)
{
if(n->data == old)
{
n->data = data;
cnt++;
}
}
return cnt;
}
// 访问
bool access_list(DoubleList* list,size_t index,TYPE *val)
{
Node* n = _index_list(list,index);
if(n == NULL) return false;
*val = n->data;
return true;
}
// 查询
int query_list(DoubleList* list,TYPE data)
{
Node* node = list->head->next;
for(int i=0;i<list->size;i++,node= node->next)
{
if(node->data == data) return i;
}
}
// 按位置删除
bool del_index_list(DoubleList* list,size_t index)
{
Node* n = _index_list(list,index);
if(n == NULL) return false;
_del_list(n);
list->size--;
return true;
}
// 按值删除
bool del_value_list(DoubleList* list,TYPE data)
{
Node* n = _value_list(list,data);
if(n = NULL) return false;
_del_list(n);
list->size--;
return true;
}
// 遍历
void show_list(DoubleList* list)
{
/*
for(int i=0;i<list->size;i++)
{
printf("%d ",list->head->next->data);
list->head->next = list->head->next->next;
}
*/
for(Node* n = list->head->next;n!=list->head;n=n->next)
{
printf("%d ",n->data);
}
printf("\n");
}
// 清理空 只是把位置放出啦,值并没有变
void clean_list(DoubleList* list)
{
while(list->size--)
{
del_index_list(list,list->size);
}
list->head->next = list->head;
list->head->prev = list->head;
}
// 销毁
void destroy_list(DoubleList* list)
{
clean_list(list);
free(list);
}
int main(int argc,const char* argv[])
{
DoubleList* list = creat_list();
for(int i=0;i<10;i++)
{
add_tail_list(list,i);
}
show_list(list);
modify_index_list(list,4,85);
modify_value_list(list,9,90);
show_list(list);
/*
int num =0;
num =query_list(list,0);
printf("%d\n",num);
*/
clean_list(list);
show_list(list);
return 0;
}
5、Linux的内核通用链表
链表的节点不能包含万物,那么久让万物来包含链表
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 遍历
#define list_for_each(n, head) \
for(n = head->next; n != head; n = n->next)
// 计算结构成员所处的结构体中的编号
#define offset(type,mem) ((int)&((type*)0)->mem)
// 计算返回某个结构体的节点成员所处的结构体的首地址
#define node_to_obj(node,type,mem)\
((type*)((void*)node-offset(type,mem)))
// 第二种遍历
#define list_for_each_entry(obj,head,mem)\
for(obj=node_to_obj(head->next,typeof(*obj),mem);\
&obj->mem!=head;\
obj=node_to_obj(obj->mem.next,typeof(*obj),mem))
// 链表节点
typedef struct Node
{
struct Node* prev;
struct Node* next;
}Node;
Node* create_list(void)
{
Node* head = malloc(sizeof(Node));
head->prev = head;
head->next = head;
return head;
}
void _add_list(Node* prev,Node* next,Node* node)
{
next->prev = node;
node->next = next;
node->prev = prev;
prev->next = node;
}
// 头添加
void add_head_list(Node* head,Node* node)
{
_add_list(head,head->next,node);
}
// 尾添加
void add_tail_list(Node* head,Node* node)
{
_add_list(head->prev,head,node);
}
// 判断链表是否为空
bool empty_list(Node* head)
{
return head == head->next;
}
// 删除节点
void _del_list(Node* node)
{
node->next->prev = node->prev;
node->prev->next = node->next;
node->next = NULL;
node->prev = NULL;
}
// 头删除
Node* del_head_list(Node* head)
{
if(empty_list(head)) return NULL;
Node* node = head->next;
_del_list(node);
return node;
}
// 尾删除
Node* del_tail_list(Node* head)
{
if(empty_list(head)) return NULL;
Node* node = head->prev;
_del_list(node);
return node;
}
/*----以上是库函数的内容,下面是用户编写的内容---*/
typedef struct Student
{
char name[20];
char sex;
char age;
char id;
Node node;
}Student;
int main(int argc,const char* argv[])
{
Student* s = malloc(sizeof(Student));
printf("====%p===%p====\n",(Student*)0,&((Student*)0)->node);
Node* head = create_list();
for(int i=0; i<10; i++)
{
Student* stu = malloc(sizeof(Student));
sprintf(stu->name,"hehe");
stu->sex = i%2?'w':'m';
stu->age = 18+i%2;
stu->id = 100+i;
add_tail_list(head,&stu->node);
// printf("%p %p\n",&stu->node,stu);
printf("%s %c %hhd %hhd\n",stu->name,stu->sex,stu->age,stu->id);
}
printf("------------\n");
for(int i=0;i<5;i++)
{
del_tail_list(head);
}
Node* n = NULL;
/*
list_for_each(n,head)
{
//printf("%p\n",n);
//Student* stu = (Student*)n;
Student* stu = node_to_obj(n,Student,node);
printf("%s %c %hhd %hhd\n",stu->name,stu->sex,stu->age,stu->id);
}
*/
Student* stu1 = NULL;
list_for_each_entry(stu1,head,node)
{
printf("%s %c %hhd %hhd\n",stu1->name,stu1->sex,stu1->age,stu1->id);
}
}