- 单向链表
-
- 有头
- 无头
- 单向循环链表
- 链式栈(无头单向链表)
- 链式队列(有头单向链表)
以上链表均只能从头往后找。即结点只有数据域和一个指向后继结点的指针域next
。
双向链表即可以从前往后或者从后往前找,这就意味着链表的结点就不能只有一个指针域next
了,还需要一个指向前期结点的指针域prior
。
1.概念
- 逻辑结构:线性结构
- 存储结构:链式存储
2. 接口实现
2.1. 定义操作双向链表的结构体
双向链表结点结构体
typedef int DLLNDataType;
typedef struct DoubleLinkListNode
{
DLLNDataType data;
struct DoubleLinkListNode *next;
struct DoubleLinkListNode *prior;
}LLN, *LL;
想要遍历该双向链表的话,除了拿到头指针后通过next
从前往后遍历,还可以拿到尾指针通过prior
从后往前遍历。
这样就意味着操作双向链表又需要两个指针,一个head
头指针,一个tail
尾指针,类比链式队列,将头尾指针放到一个操作双向链表的结构体里面去。
操作双向链表的结构体
typedef struct DoubleLinkList
{
LL head; // 头指针
LL tail; // 尾指针
int len; // 记录链表长度
} DLL;
假如链表有一百个结点那么长,我想删除98
位结点,如果结构体中有链表的长度,可以更加方便的使用尾指针进行操作。
2.2. 创建空的双向链表
2.3. 插入
插入位置结点与其前驱以及新结点三者之间建立联系示意图:
向双向链表指定位置插入数据
// 3. 向双向链表指定位置插入数据
int DLLInsert(DLL *PD, int post, DLLNDataType data)
{
// 3.1 容错判断 [0, PD->len]
if (post < 0 || post > PD->len)
{
printf("DLLInsert failed, post not at [0, PD->len].\n");
return -1;
}
// 3.2 创建新节点保存插入数据
LL PNew = (LL)malloc(sizeof(LLN));
if (NULL == PNew)
{
printf("DLLInsert failed, PNew malloc err.\n");
return -1;
}
PNew->data = data;
PNew->next = PNew->prior = NULL;
// 3.3 判断插入位置(三种情况)
// 3.3.1 尾插(尾结点和新结点互相指)
if (post == PD->len)
{
// 互相指
PNew->prior = PD->tail;
PD->tail->next = PNew;
// 尾指针tail后移
PD->tail = PNew;
// 长度++
PD->len++;
}
// 3.3.2 中间插
else
{
// 定义伪指针,代替头指针PD->head或尾指针PD->tail去移动
LL PTemp = NULL;
// 中间插前半段,PTemp为伪头指针,代替头指针移动。
if (post < PD->len / 2)
{
// PTemp代替头指针移动
PTemp = PD->head;
// 移动伪头指针
for (int i = 0; i <= post; i++)
PTemp = PTemp->next;
}
// 中间插后半段,PTemp为伪尾指针,代替尾指针移动。
else
{
// PTemp代替尾指针移动
PTemp = PD->tail;
// 移动伪尾指针
for (int i = PD->len-1; i > post; i--)
PTemp = PTemp->prior;
}
// 进行插入动作,先前再后
// 前
PNew->prior = PTemp->prior;
PTemp->prior->next = PNew;
// 后
PNew->next = PTemp;
PTemp->prior = PNew;
// 插入完成后长度+1
PD->len++;
}
return 0;
}
DoubleLinkList.h文件
双向链表功能函数
插入函数 | int DLLInsert(DLL *PD, int post, DLLNDataType data); |
打印函数 | void DLLPrint(DLL PD); |
删除函数(按位置) | int DLLDeletePost(DLL *PD, int post); |
查找内容函数(返回下标) | int DLLFind(DLL PD, DLLNDataType data); |
修改内容函数 | int DLLModify(DLL *PD , int post , DLLNDataType data); |
删除函数(按内容) | void DLLDeleteData(DLL *PD, DLLNDataType data); |
#ifndef _DOUBLELINKLIST_H_
#define _DOUBLELINKLIST_H_
#include<stdio.h>
#include<stdlib.h>
typedef int DLLNDataType;
typedef struct DoubleLinkListNode
{
DLLNDataType data;
struct DoubleLinkListNode *next;
struct DoubleLinkListNode *prior;
}LLN, *LL;
typedef struct DoubleLinkList
{
LL head;
LL tail;
int len;
}DLL;
DLL *DLLInit();
int DLLInsert(DLL *PD, int post, DLLNDataType data);
void DLLPrint(DLL PD);
int DLLDeletePost(DLL *PD, int post);
int DLLFind(DLL PD, DLLNDataType data);
int DLLModify(DLL *PD , int post , DLLNDataType data);
void DLLDeleteData(DLL *PD, DLLNDataType data);
#endif
DoubleLinkList.c文件
#include "DoubleLinkList.h"
DLL *DLLInit()
{
DLL *PD = (DLL *)malloc(sizeof(DLL));
if (NULL == PD)
{
printf("DLLInit failed, PD malloc err.\n");
return NULL;
}
PD->head = PD->tail = (LL)malloc(sizeof(LLN));
if (NULL == PD->head || NULL == PD->tail)
{
printf("DLLInit failed, PD->head or PD->tail malloc err.\n");
return NULL;
}
PD->head->next = PD->head->prior = NULL;
PD->len = 0;
return PD;
}
int DLLInsert(DLL *PD, int post, DLLNDataType data)
{
if (post < 0 || post > PD->len)
{
printf("DLLInsert failed, post illegal.\n");
return -1;
}
LL PNew = (LL)malloc(sizeof(LLN));
if (NULL == PNew)
{
printf("DLLInsert failed, PNew malloc err.\n");
return -1;
}
PNew->data = data;
PNew->next = PNew->prior = NULL;
if (post == PD->len) //尾插
{
PD->tail->next = PNew;
PNew->prior = PD->tail;
PD->tail = PNew;
PD->len++;
}
else //中间插入
{
LL PTemp = NULL;
if (post < PD->len / 2) //len前半段插入
{
PTemp = PD->head;
for (int i = 0; i <= post; i++)
PTemp = PTemp->next;
}
else
{
PTemp = PD->tail;
for (int i = PD->len - 1; i > post; i--) //i = 0 ; i<len-post-1;i++;
PTemp = PTemp->prior;
}
PTemp->prior->next = PNew;
PNew->prior = PTemp->prior;
PTemp->prior = PNew;
PNew->next = PTemp;
PD->len++;
}
return 0;
}
void DLLPrint(DLL PD)
{
if (PD.head == PD.tail)
{
printf("DLLPrint failed, DLL is empty.\n");
return;
}
printf("DoubleLinkList data is ");
while (PD.head != PD.tail)
{
PD.head = PD.head->next;
printf("%d ", PD.head->data);
}
putchar(10);
}
int DLLDeletePost(DLL *PD, int post)
{
if (post < 0 || post >= PD->len)
{
printf("DLLDeletePost failed, post illegal.\n");
return -1;
}
if (post == PD->len - 1) //尾删
{
PD->tail = PD->tail->prior;
free(PD->tail->next);
PD->tail->next = NULL;
}
else
{
LL PTemp = NULL;
if (post < PD->len / 2) //len前半段删除
{
PTemp = PD->head;
for (int i = 0; i <= post; i++)
PTemp = PTemp->next;
}
else
{
PTemp = PD->tail;
for (int i = 0; i < PD->len - post - 1; i++)
PTemp = PTemp->prior;
}
PTemp->prior->next = PTemp->next;
PTemp->next->prior = PTemp->prior;
free(PTemp);
PTemp = NULL;
PD->len--;
}
return 0;
}
int DLLFind(DLL PD, DLLNDataType data)
{
if (PD.head == PD.tail)
{
printf("DLLFind failed, DLL is empty.\n");
return -1;
}
int post = 0;
while (PD.head != PD.tail)
{
PD.head = PD.head->next;
if (data == PD.head->data)
{
printf("data %d's post is %d\n", data, post);
}
post++;
}
return -1;
}
int DLLModify(DLL *PD, int post, DLLNDataType data)
{
if (post < 0 || post >= PD->len)
{
printf("DLLDeletePost failed, post illegal.\n");
return -1;
}
LL PTemp = NULL;
if (post < PD->len / 2) //len前半段删除
{
PTemp = PD->head;
for (int i = 0; i <= post; i++)
PTemp = PTemp->next;
}
else
{
PTemp = PD->tail;
for (int i = 0; i < PD->len - post - 1; i++)
PTemp = PTemp->prior;
}
PTemp->data = data;
return 0;
}
void DLLDeleteData(DLL *PD, DLLNDataType data)
{
LL H = PD->head->next;
while (H)
{
if (H->data == data)
{
if (H == PD->tail)
{
PD->tail = PD->tail->prior;
free(PD->tail->next);
PD->tail->next = NULL;
}
else
{
H->prior->next = H->next;
H->next->prior = H->prior;
LL PDel = H;
H = H->next;
free(PDel);
PDel = NULL;
PD->len--;
}
}
else
H = H->next;
}
}
test.c文件
#include "DoubleLinkList.h"
int main(int argc, char const *argv[])
{
DLL *PD = DLLInit();
DLLInsert(PD, 0, 101);
DLLInsert(PD, 0, 102);
DLLInsert(PD, 0, 103);
DLLInsert(PD, 0, 104);
DLLInsert(PD, 0, 105);
DLLInsert(PD, 0, 101);
DLLInsert(PD, 0, 101);
DLLInsert(PD, 0, 101);
DLLInsert(PD, 0, 101);
DLLInsert(PD, 0, 101);
DLLPrint(*PD);
DLLInsert(PD, 5, 102);
DLLInsert(PD, 6, 103);
DLLInsert(PD, 7, 104);
DLLInsert(PD, 8, 105);
DLLPrint(*PD);
DLLDeletePost(PD, 0);
DLLPrint(*PD);
DLLFind(*PD, 102);
DLLModify(PD, 3, 200);
DLLPrint(*PD);
DLLDeleteData(PD,101);
DLLPrint(*PD);
return 0;
}
运行结果
makefile文件
CC=gcc
OBJS=test.o DoubleLinkList.o
CFLAGS=-c -g -Wall
# CC=none-linux-gnueabi-gcc
test:$(OBJS)
$(CC) -o test $(OBJS)
%.o:%.c
$(CC) $(CFLAGS) $< -o $@
.PHONY:clean
clean:
$(RM) *.o test