链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。链表可以在多种编程语言中实现。像Lisp和Scheme这样的语言的内建数据类型中就包含了链表的存取和操作。程序语言或面向对象语言,如C,C++和Java依靠易变工具来生成链表。
![](https://img2020.cnblogs.com/blog/1725049/202011/1725049-20201106192557687-320043938.png)
一.声明链表
每个结点包括两个部分:一个是存储数据元素的数据域(data),另一个是存储下一个结点地址的指针域(next)。
typedef struct Node { int data; struct Node *next; } node;
二.初始化链表
1.头插法创建链表,头插法顾名思义就是从把新添加的元素放在链表的头部,例如新添加的S元素作为链表的头节点,放在第一位
node * head_insert(int n){ node *head=(node *)malloc(sizeof(node)); //创建头节点 head->data=0; head->next=NULL; for (int i = 0; i < n; i++) { node *body=(node *)malloc(sizeof(node)); //创建一个新的节点 body->data=i+1; body->next=head->next; //与尾插法的区别就在这里,新插入元素的next指向head的next head->next=body; } return head; }
///打印的数据为0->5->4->3->2->1->null //新添加的元素最后输出
2.尾插法,就是常规的操作,新添加的元素放在链表的最后
node * tail_insert(int n){ node *head=(node *)malloc(sizeof(node)); //创建头节点 head->data=0; head->next=NULL; node *p=head; //声明一个指针指向头结点,用于遍历链表(这里是单个的节点) for (int i = 0; i < n; i++) { node *body=(node *)malloc(sizeof(node)); body->data=i+1; p->next=body; p=p->next; //指针后移,移动到下一个节点 } return head; //head为整个链表 }
///0->1->2->3->4->5->null //新添加的元素在链表的尾部
总结:头插和尾插的根本区别在于头节点,头节点不变化的为尾插法,头节点变动的(变为新插入的节点)为尾插法
三.打印链表
void print_list(node *head){ while (head) { printf("%d->",head->data); head=head->next; //后移指针,完成切换 } printf("null "); }
四.查找节点
//查找节点 node * find_list(node *head,int x){ while (head&&head->data!=x) { head=head->next; //如果不是最后的节点或节点的值不相等,则指针后移 } if (head) return head; return NULL; }
五.删除元素
//删除根据索引位置删除链表的位置 void delete_list(node *head,int i){ int j=0; while (head&&j<i-1) { head=head->next; j++; } //head->next=head->next->next; node *p=(node *)malloc(sizeof(node)); p=head->next; head->next=p->next; free(p); }
六.插入元素
//向链表中插入值为n的元素 node * insert_list(node *head,int n,int i){ int j=0; while (head&&j<i-1) { head=head->next; j++; } if (!head) { return NULL; } node *p=(node *)malloc(sizeof(node)); //创建一个新的节点 p->data=n; p->next=head->next; head->next=p; return p; }
整体代码
#include <stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node *next; } node; //创建一个头节点 node * create_list(int x){ node *p=(node *)malloc(sizeof(node)); p->data=x; p->next=NULL; return p; } node * init_list(int n){ node *head=(node *)malloc(sizeof(node)); //创建头节点 head->data=0; head->next=NULL; node *p=head; //声明一个指针指向头结点,用于遍历链表(这里是单个的节点) for (int i = 0; i < n; i++) { node *body=(node *)malloc(sizeof(node)); body->data=i+1; p->next=body; p=p->next; //指针后移,移动到下一个节点 } return head; //head为整个链表 } //链表添加节点 void add_list(node *head,int x){ if(!head)return; while (head->next) { head=head->next; //当指针不为空时,表明不是最后的节点,向后移动 } node *p=(node *)malloc(sizeof(node)); //创建一个新的节点 p->data=x; p->next=NULL; head->next=p; //关联链表 } //查找节点 node * find_list(node *head,int x){ while (head&&head->data!=x) { head=head->next; //如果不是最后的节点或节点的值不相等,则指针后移 } if (head) return head; return NULL; } //打印链表的值 void print_list(node *head){ while (head) { printf("%d->",head->data); head=head->next; //后移指针,完成切换 } printf("null "); } //向链表中插入值为n的元素 node * insert_list(node *head,int n,int i){ int j=0; while (head&&j<i-1) { head=head->next; j++; } if (!head) { return NULL; } node *p=(node *)malloc(sizeof(node)); //创建一个新的节点 p->data=n; p->next=head->next; head->next=p; return p; } //头插法 node * head_insert(int n){ node *head=(node *)malloc(sizeof(node)); //创建头节点 head->data=0; head->next=NULL; for (int i = 0; i < n; i++) { node *body=(node *)malloc(sizeof(node)); //创建一个新的节点 body->data=i+1; body->next=head->next; head->next=body; } return head; } //删除根据索引位置删除链表的位置 void delete_list(node *head,int i){ int j=0; while (head&&j<i-1) { head=head->next; j++; } //head->next=head->next->next; node *p=(node *)malloc(sizeof(node)); p=head->next; head->next=p->next; free(p); } //获取链表中的某一元素 node * get_elem(node *head,int i){ int j=0; while (head&&j<i-1) { head=head->next; j++; } if (j!=i-1) { return NULL; } printf("%d->",head->data); return head; } //删除链表中所有的值为key的节点 void deleteAllKey_list(node *head,int key){ node *p,*q; p=head; q=head->next; while (q!=NULL) { if (q->data==key) { p->next=q->next; free(q); q=p->next; }else { p=p->next; q=q->next; } } } void deleteAllSameKey_list(node *head){ node *p=head->next,*q,*r; while (p!=NULL) { q=p; while (q->next) { if (q->next->data==p->data) { r=q->next; q->next=r->next; free(r); }else { q=q->next; } } p=p->next; } } void main(){ // node *head =create_list(1); // add_list(head,5); // add_list(head,3); // add_list(head,7); // add_list(head,8); // insert_list(head,8,2); // add_list(head,7); // print_list(head); // // deleteAllKey_list(head,7); // deleteAllSameKey_list(head); // print_list(head); node *list=init_list(5); // node *list=head_insert(5); print_list(list); }