图解无头单向非循环链表和带头双向循环链表
链表是一种重要的数据结构,其概念:链表是一种 物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链
接次序实现的 。
这里介绍两种链表:
- 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。
- 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。
单链表(单向不带头)
数据节点和头结点
typedef int Data; //数据类型
typedef struct lists{
//自定义单链表结构体
Data _data;
struct lists* _next;
}lists;
//自定义头结点
typedef struct firstlist{
//用来找到并操作链表,必须从头开始
struct lists* _head;
}firstlist;
新增节点函数和初始化
//结构体初始化
void init(firstlist* flist){
if (flist == NULL){
return flist;
}
flist->_head = NULL; //数据设为空
}
lists* xinzeng(Data _data){
//将一个数据传入一个新链表,返回新链表的地址
lists* newlist = (lists*)malloc(sizeof(lists));
newlist->_data = _data;
newlist->_next = NULL;
return newlist;
}
基本操作
1.尾插
//尾插
void weicha(firstlist* lit,Data data){
//将data尾插到lit链表中
//传firstlist是因为知道头结点地址就可以操作链表了
if (lit == NULL){
//如果是空链表直接返回null
return;
}
//空链表插入第一个数据
if (lit->_head == NULL){
lit->_head = xinzeng(data);
}
else{
//不是空链表则需要遍历
lists* list = lit->_head;
//因为_head是第一个元素的地址,所以要lists*
while (list->_next != NULL){
list = list->_next;
}
list->_next = xinzeng(data);
}
}
2.尾删
//尾删
void weishan(firstlist* flist){
if (flist == NULL||flist->_head==NULL){
return;
}
//用两个变量one 和two来操作
lists* one = flist->_head;
lists* two = NULL;
if (one->_next != NULL){
two = one;
one = one->_next;
}
free(one);
if (two == NULL){
//这种是只有头节点,two就没变
flist->_head = NULL;
}
else{
two->_next = NULL;
}
}
3.头插
//头插
void toucha(firstlist* flist,Data data){
if (flist == NULL){
return;
}
if (flist->_head == NULL){
flist->_head = xinzeng(data);
}
else{
lists* b = xinzeng(data);
b->_next = flist->_head;
flist->_head = b;
}
}
4.头删
//头删
void toushan(firstlist* list){
if (list==NULL){
return;
}
if (list->_head == NULL){
return;
}
else{
struct lists* next = list->_head->_next;
free(list->_head);
list->_head = next;
}
}
5.任意位置新增节点
//在哪新增一个节点
void jiaru(lists* a,Data data){
//用不到头节点所以直接操作
lists* list = xinzeng(data);
list->_next = a->_next;
a->_next = list;
}
6.任意位置删除
//删除那个位置的下一个
void shanchu(lists* a,Data data){
lists* next = a->_next;
if (next == NULL){
return;
}
lists* next2 = a->_next->_next;
free(next);
a->next=next2;
}
7.寻找数据
lists* find(firstlist* flist, Data data){
if (flist == NULL || flist->_head == NULL){
return;
}
while (flist->_head){
if (flist->_head->_data == data){
return flist->_head;
}
else{
flist->_head = flist->_head->_next;//思路类似于头删,但没有free就不是删除
}
return NULL;//一直没找到返回空
}
}
8.销毁链表
//销毁链表
void xiaohui(firstlist* flist){
if (flist == NULL || flist->_head == NULL){
return;
}
while (flist->_head){
//循环头删
flist->_head = flist->_head->_next;
free(flist->_head);
}
flist->_head = NULL;
}
带头双向循环链表
其中头结点没有数据,所以
空表:
非空表:
数据节点和头节点
typedef int Data;
typedef struct lists{
//数据节点
Data _data;
struct lists* _prev;
struct lists* _next;
}lists;
typedef struct headlist{
//头结点
struct lists* _head;
}headlist;
新增节点函数和初始化
1.新增节点
lists* create(Data data){
//创造新节点
lists* new = (lists*)malloc(sizeof(lists));
new->_data = data;
new->_next = NULL;
new->_prev = NULL;
return new;
}
2.初始化链表
void init(headlist* hlist){
if (hlist == NULL){
return;
}
hlist->_head = create(0);
hlist->_head->_next = hlist->_head->_prev = hlist->_head;
}
基本操作(删除和增加)
1.尾插
//尾插
void weicha(headlist* hlist, Data data){
if (hlist == NULL){
return;
}
//_head ..... last + new
lists* new = create(data);
lists* last=hlist->_head->_prev;
last->_next=new;
new->_prev = last;
new->_next = hlist->_head;
hlist->_head->_prev = new;
}
2.尾删
//尾删
void weishan(headlist* hlist){
if (hlist == NULL){
return;
}
if (hlist->_head->_next = hlist->_head->_prev = hlist->_head){
return;
}
lists* last = hlist->_head->_prev;//最后一个
lists* prev=hlist->_head->_prev->_prev;//倒数第二个
free(last);
hlist->_head->_prev = prev;
prev->_next = hlist->_head;
}
3.头插
//头插
void toucha(headlist* hlist, Data data){
if (hlist == NULL){
return;
}
lists* new=create(data);
lists* old=hlist->_head->_next;
//_head (new) old
hlist->_head->_next = new;
new->_prev = hlist->_head;
new->_next = old;
old->_prev = new;
}
4.头删
//头删
void toushan(headlist* hlist){
if (hlist->_head->_next = hlist->_head->_prev = hlist->_head){
return;
}
if (hlist == NULL){
return;
}
lists* first = hlist->_head->_next;
lists* second = hlist->_head->_next->_next;
//_head first(删) second
second->_prev = hlist->_head;
hlist->_head->_next = second;
free(first);
}
5.在任意位置删除
//在任意位置删除
void anywheredelete(headlist* hlist, lists* list){
if (hlist->_head = list){
return;
}
if (hlist == NULL){
return;
}
//prev list(删掉) next
lists* prev = list->_prev;
lists* next = list->_next;
prev->_next = next;
next->_prev = prev;
free(list);
}
6.在任意位置增加
//在任意位置增加
void anywhereadd(headlist* hlist, lists* list, Data data){
if (hlist == NULL){
return;
}
//prev new list
lists* new = create(data);
lists* prev = list->_prev;
prev->_next = new;
new->_prev = prev;
new->_next = list;
list->_prev = new;
}
顺序表和链表的评价
顺序表链接:link
1.顺序表空间连续,所以支持随机访问.
链表空间不连续,不支持随机访问.
2.顺序表插入删除效率低
链表任意位置插入删除高效
源代码
单链表
#include<stdio.h>
#include<windows.h>
typedef int Data; //数据类型
typedef struct lists{
//自定义单链表结构体
Data _data;
struct lists* _next;
}lists;
//自定义头结点
typedef struct firstlist{
//用来找到并操作链表,必须从头开始
struct lists* _head;
}firstlist;
//结构体初始化
void init(firstlist* flist){
if (flist == NULL){
return flist;
}
flist->_head = NULL; //数据设为空
}
lists* xinzeng(Data _data){
//将一个数据传入一个新链表,返回新链表的地址
lists* newlist = (lists*)malloc(sizeof(lists));
newlist->_data = _data;
newlist->_next = NULL;
return newlist;
}
//尾插
void weicha(firstlist* lit,Data data){
//将data尾插到lit链表中
//传firstlist是因为知道头结点地址就可以操作链表了
if (lit == NULL){
//如果是空链表直接返回null
return;
}
//空链表插入第一个数据
if (lit->_head == NULL){
lit->_head = xinzeng(data);
}
else{
//不是空链表则需要遍历
lists* list = lit->_head;
//因为_head是第一个元素的地址,所以要lists*
if (list->_next != NULL){
list = list->_next;
}
list->_next = xinzeng(data);
}
}
//尾删
void weishan(firstlist* flist){
if (flist == NULL||flist->_head==NULL){
return;
}
//用两个变量one 和two来操作
lists* one = flist->_head;
lists* two = NULL;
if (one->_next != NULL){
two = one;
one = one->_next;
}
free(one);
if (two == NULL){
//这种是只有头节点,two就没变
flist->_head = NULL;
}
else{
two->_next = NULL;
}
}
//头插
void toucha(firstlist* flist,Data data){
if (flist == NULL){
return;
}
if (flist->_head == NULL){
flist->_head = xinzeng(data);
}
else{
lists* b = xinzeng(data);
b->_next = flist->_head;
flist->_head = b;
}
}
//头删
void toushan(firstlist* list){
if (list==NULL){
return;
}
if (list->_head == NULL){
return;
}
else{
struct lists* next = list->_head->_next;
free(list->_head);
list->_head = next;
}
}
//在哪新增一个节点
void jiaru(lists* a,Data data){
//用不到头节点所以直接操作
lists* list = xinzeng(data);
list->_next = a->_next;
a->_next = list;
}
//删除那个位置的下一个
void shanchu(lists* a,Data data){
lists* next = a->_next;
if (next == NULL){
return;
}
lists* next2 = a->_next->_next;
next = next2;
free(next);
}
//找到某数据
lists* find(firstlist* flist, Data data){
if (flist == NULL || flist->_head == NULL){
return;
}
while (flist->_head){
if (flist->_head->_data == data){
return flist->_head;
}
else{
flist->_head = flist->_head->_next;//思路类似于头删,但没有free就不是删除
}
return NULL;//一直没找到返回空
}
}
//销毁链表
void xiaohui(firstlist* flist){
if (flist == NULL || flist->_head == NULL){
return;
}
while (flist->_head){
//循环头删
flist->_head = flist->_head->_next;
free(flist->_head);
}
flist->_head = NULL;
}
双向链表
#include<stdio.h>
typedef int Data;
typedef struct lists{
//数据节点
Data _data;
struct lists* _prev;
struct lists* _next;
}lists;
typedef struct headlist{
//头结点
struct lists* _head;
}headlist;
lists* create(Data data){
//创造新节点
lists* new = (lists*)malloc(sizeof(lists));
new->_data = data;
new->_next = NULL;
new->_prev = NULL;
return new;
}
void init(headlist* hlist){
if (hlist == NULL){
return;
}
hlist->_head = create(0);
hlist->_head->_next = hlist->_head->_prev = hlist->_head;
}
//尾插
void weicha(headlist* hlist, Data data){
if (hlist == NULL){
return;
}
//_head ..... last + new
lists* new = create(data);
lists* last=hlist->_head->_prev;
last->_next=new;
new->_prev = last;
new->_next = hlist->_head;
hlist->_head->_prev = new;
}
//尾删
void weishan(headlist* hlist){
if (hlist == NULL){
return;
}
if (hlist->_head->_next = hlist->_head->_prev = hlist->_head){
return;
}
lists* last = hlist->_head->_prev;//最后一个
lists* prev=hlist->_head->_prev->_prev;//倒数第二个
free(last);
hlist->_head->_prev = prev;
prev->_next = hlist->_head;
}
//头插
void toucha(headlist* hlist, Data data){
if (hlist == NULL){
return;
}
lists* new=create(data);
lists* old=hlist->_head->_next;
//_head (new) old
hlist->_head->_next = new;
new->_prev = hlist->_head;
new->_next = old;
old->_prev = new;
}
//头删
void toushan(headlist* hlist){
if (hlist->_head->_next = hlist->_head->_prev = hlist->_head){
return;
}
if (hlist == NULL){
return;
}
lists* first = hlist->_head->_next;
lists* second = hlist->_head->_next->_next;
//_head first(删) second
second->_prev = hlist->_head;
hlist->_head->_next = second;
free(first);
}
//在任意位置删除
void anywheredelete(headlist* hlist, lists* list){
if (hlist->_head = list){
return;
}
if (hlist == NULL){
return;
}
//prev list(删掉) next
lists* prev = list->_prev;
lists* next = list->_next;
prev->_next = next;
next->_prev = prev;
free(list);
}
//在任意位置增加
void anywhereadd(headlist* hlist, lists* list, Data data){
if (hlist == NULL){
return;
}
//prev new list
lists* new = create(data);
lists* prev = list->_prev;
prev->_next = new;
new->_prev = prev;
new->_next = list;
list->_prev = new;
}