双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
单向链表和双向链表优缺点:
双向链表:增加删除节点复杂,需要多分配一个指针存储空间。
双向链表:从双向链表中的任意一个结点开始,都可以很方便地访问前驱结点和后继结点。
单向链表:结点的删除非常方便,不需要像线性结构那样移动剩下的数据,但是平均的访问效率低于线性表。
单向链表:单个结点创建非常方便,普通的线性内存通常在创建的时候就需要设定数据的大小,结点的访问方便,可以通过循环或者递归的方法访问到任意数据。
代码如下:
头文件:
#ifndef __FY_LINKLIST_H
#define __FY_LINKLIST_H
typedef int data_t;
struct node {
data_t data;
struct node *prev;
struct node *next;
};
//创建一个结点
struct node *creatNode(data_t data);
//创建一个双向链表
struct node *creatList(void);
//指定位置插入一个数据
int list_insert(struct node *H,int pos,data_t data);
//删除指定位置的结点
int list_delete(struct node *H,int pos);
//查找指定位置的元素
struct node *list_get(struct node *H,int pos);
//销毁双向链表
struct node *list_free(struct node *H);
//遍历链表
int list_show(struct node *H);
#endif
C文件:
#include "linklist.h"
#include "stdio.h"
#include "stdlib.h"
//创建一个结点
struct node *creatNode(data_t data){
struct node *newnode = (struct node *)malloc(sizeof(struct node));
if(newnode == NULL) {
printf("创建结点失败,申请内存为空!\n");
return NULL;
}
newnode->data = data;
newnode->prev = NULL;
newnode->next = NULL;
return newnode;
}
//创建一个双向链表(头结点)
struct node *creatList(void){
struct node* newnode = (struct node *)malloc(sizeof(struct node));
if(newnode == NULL){
printf("创建双向链表失败,申请内存为空!\n");
return NULL;
}
newnode->data = 0;
newnode->next = newnode->prev = NULL;
return newnode;
}
//获取双向链表中指定位置元素
/*
定义头结点的位置为-1
*/
struct node *list_get(struct node *H,int pos){
if(H == NULL) return NULL;
if(pos <-1) return NULL;
int i=-1;
struct node *p = H;
while(i<pos && p!=NULL){
p = p->next;
i++;
}
if(i!=pos) return NULL;
return p;
}
//指定位置插入一个数据
/*
定义头结点位置为-1
*/
int list_insert(struct node *H,int pos,data_t data){
if(H==NULL) return -1;
if(pos<0) return -1;
struct node *p = list_get(H,pos-1);//找到该位置的前驱结点
if(p==NULL) return -1;
struct node *newnode = creatNode(data);
//p结点是肯定存在的
newnode->prev = p;
newnode->next = p->next;
if(p->next != NULL)//p结点存在后继
p->next->prev = newnode;
p->next = newnode;
return 0;
}
//删除指定位置的结点
int list_delete(struct node *H,int pos){
if(H==NULL) return -1;
if(pos<0) return -1;
struct node *p = list_get(H,pos);
if(p==NULL) return -1;
//p结点是肯定存在的,并且肯定是有前驱的(至少头结点不能被删除)
p->prev->next = p->next;
if(p->next != NULL){ //存在后继结点的情况下
p->next->prev = p->prev;
}
free(p);
return 0;
}
//销毁双向链表
struct node *list_free(struct node *H){
if(H==NULL) return NULL;
struct node *p = H;
while(H->next != NULL){
H = H->next;
free(p);
p = H;
}free(p);
return NULL;
}
//遍历链表
int list_show(struct node *H){
if(H == NULL) return -1;
struct node *p = H->next;
while(p!=NULL){
printf("%d ",p->data);
p = p->next;
}printf("\n");
return 0;
}
测试代码:
#include "stdio.h"
#include "stdlib.h"
#include "linklist.h"
int main(){
int pos;
data_t value;
struct node *H = creatList();
printf("**********************指定位置插入结点测试*********************\n");
while(1){
printf("请按顺序输入位置和数据,输入-1 -1结束测试:");
scanf("%d %d",&pos,&value);
if(pos == -1 && value == -1) {
printf("测试结束!\n");
break;
}
int res;
res = list_insert(H,pos,value);
if(res==0){
printf("\n插入成功,新链表为:");
list_show(H);
}
else{
printf("插入失败!\n");
}
}
H = list_free(H);
H = creatList();
for(int i=0;i<10;i++){
list_insert(H,i,i);
}
list_show(H);
printf("***********************指定位置查找元素测试********************\n");
while(1){
printf("请输入一个位置,输入-1结束测试:");
scanf("%d",&pos);
if(pos == -1){
printf("测试结束!\n");
break;
}
struct node *p = list_get(H,pos);
if(p == NULL){
printf("查找失败!\n");
}
else{
printf("查找的元素为:%d\n",p->data);
}
}
printf("***********************删除指定位置结点测试********************\n");
while(1){
printf("请按顺序输入位置和数据,输入-1结束测试:");
scanf("%d",&pos);
if(pos == -1) {
printf("测试结束!\n");
break;
}
int res;
res = list_delete(H,pos);
if(res == 0){
printf("删除成功,新链表为:");
list_show(H);
}
else{
printf("删除失败!\n");
}
}
printf("hell world!\n");
return 0;
}
测试结果:
指定位置插入
指定位置查找
指定位置删除
By urien 2021年2月4日 17:52:16