双链表与循环链表

1.双链表

双链表是指在单链表的基础上,每一个结构体中多出来一个指针用来指向上一个结构体。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct Lnode {
	int value;
	struct Lnode* next;
	struct Lnode* previous;
}Lnode;

typedef struct DoubleList {
	Lnode* head;
	Lnode* tail;
	int numofele;
}List;

List* CreatList() {
	List* ret = (List*)malloc(sizeof(List));
	if (ret == NULL) {
		perror("malloc:");
		return NULL;
	}
	ret->numofele = 0;
	ret->head = (Lnode*)malloc(sizeof(Lnode));
	if (ret->head == NULL) {
		perror("malloc:");
		return NULL;
	}
	ret->tail = (Lnode*)malloc(sizeof(Lnode));
	if (ret->tail == NULL) {
		perror("malloc:");
		return NULL;
	}
	ret->head->next = NULL;
	ret->head->previous = NULL;
	ret->tail->previous = ret->head;
	ret->tail->next = NULL;
	return ret;
}

void DestroyList(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	Lnode* tmp = l->head;
	while (tmp) {
		Lnode* p = tmp->next;
		free(tmp);
		tmp = p;
	}
	free(l);
	l = NULL;
}

List* ClearList(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return NULL;
	}
	l->numofele = 0;
	Lnode* tmp = l->head->next;
	while (tmp != l->tail) {
		Lnode* p = tmp->next;
		free(tmp);
		tmp = p;
	}
	l->head->next = NULL;//为了测试双链表删除等算法的边界情况,这里不使用尾节点,加入尾节点操作会更方便
	l->tail->previous = l->head;
	return l;
}

bool IsEmpty(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return false;
	}
	return l->numofele == 0;
}

int GetListLength(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return -1;
	}
	return l->numofele;
}

int GetElem(List* l, int pos) {//获得表中第pos个元素
	if (l == NULL) {
		printf("表不存在\n");
		return -1;
	}
	if (IsEmpty(l)) {
		printf("表为空\n");
		return -1;
	}
	if (pos<1 || pos>l->numofele) {
		printf("不存在第 %d 个元素\n", pos);
		return -1;
	}
	int count = pos;
	Lnode* tmp = l->head;
	while (count--) {
		tmp = tmp->next;
	}
	return tmp->value;
}

Lnode* GetElemPos(List* l, int k) {
	if (l == NULL) {
		printf("表不存在\n");
		return NULL;
	}
	if (IsEmpty(l)) {
		printf("表为空\n");
		return NULL;
	}
	Lnode* tmp = l->head->next;
	while (tmp != l->tail) {
		if (tmp->value == k)
			return tmp;
		tmp = tmp->next;
	}
	printf("不存在元素 %d\n", k);
	return NULL;
}

Lnode* GetPre(List* l, int k) {
	if (l == NULL) {
		printf("表不存在\n");
		return NULL;
	}
	if (IsEmpty(l)) {
		printf("表为空\n");
		return NULL;
	}
	Lnode* tmp = l->head;
	while (tmp->next != l->tail) {
		if (tmp->next->value == k)
			return tmp;
		tmp = tmp->next;
	}
	printf("不存在元素 %d,所以没有前驱\n", k);
	return NULL;
}

//在指定结点后插
void BackInsert(List* l, Lnode* object, int k) {

	if (l == NULL) {
		printf("表为空\n");
		return;
	}
	Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
	if (tmp == NULL) {
		perror("malloc");
		return;
	}
	if (object->next) {
		tmp->next = object->next;
		tmp->previous = object;
		tmp->next->previous = tmp;
		object->next = tmp;
		tmp->value = k;
	}
	else {//带有尾节点的双链表不需要判断这一层
		tmp->next = NULL;
		tmp->previous = object;
		object->next = tmp;
		tmp->value = k;
	}

}

//在指定结点前插
void PreInsert(List* l, Lnode* object, int k) {

	if (l == NULL) {
		printf("表为空\n");
		return;
	}
	Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
	if (tmp == NULL) {
		perror("malloc");
		return;
	}
	Lnode* pre = object->previous;
	tmp->next = object;
	tmp->previous = pre;
	pre->next = tmp;
	object->previous = tmp;
	tmp->value = k;

}

//在指定位置插入
void Insert(List* l, int k, int pos) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (pos<1 || pos>l->numofele + 1) {
		printf("插入位置不合法\n");
		return;
	}
	int count = pos - 1;
	Lnode* tmp = l->head;
	while (count--) {
		tmp = tmp->next;
	}
	Lnode* p = (Lnode*)malloc(sizeof(Lnode));
	if (p == NULL) {
		perror("malloc:");
		return;
	}
	//如果不使用尾节点,对最后一个元素进行插入和删除就需要单独处理
	if (tmp->next) {
		p->next = tmp->next;
		tmp->next = p;
		p->previous = tmp;
		p->next->previous = p;
		p->value = k;
		l->numofele++;
	}
	else {
		tmp->next = p;
		p->next = NULL;
		p->previous = tmp;
		p->value = k;
		l->numofele++;
	}
}

//删除指定结点
int ObjectDelete(List* l, Lnode* object) {

	int ret = object->value;

	if (l == NULL) {
		printf("表为空\n");
		return -1;
	}
	Lnode* pre = object->previous;
	if (object->next) {
		pre->next = object->next;
		object->next->previous = pre;
		free(object);
		object = NULL;
	}
	else {
		pre->next = NULL;
		free(object);
		object = NULL;
	}

	return ret;

}

//按位置删除结点
int Delete(List* l, int i) {
	if (l == NULL) {
		printf("表不存在\n");
		return -1;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法删除\n");
		return -1;
	}
	Lnode* tmp = l->head;
	while (i--) {
		tmp = tmp->next;
	}
	int ret = tmp->value;
	Lnode* pre = tmp->previous;
	if (tmp->next) {
		pre->next = tmp->next;
		tmp->next->previous = pre;
		free(tmp);
		tmp = NULL;
	}
	else {
		pre->next = NULL;
		free(tmp);
		tmp = NULL;
	}
	return ret;
}

void Print(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法打印\n");
		return;
	}
	Lnode* tmp = l->head->next;
	while (tmp) {
		printf("%d ", tmp->value);
		tmp = tmp->next;
	}
	printf("  元素数量 = %d", l->numofele);
	printf("\n");
}

void ReversePrint(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法打印\n");
		return;
	}
	Lnode* tmp = l->tail->previous;
	while (tmp != l->head) {
		printf("%d ", tmp->value);
		tmp = tmp->previous;
	}
	printf("  元素数量 = %d\n", l->numofele);
}

int main() {

	List* l = CreatList();
	Print(l);

	for (int i = 0; i < 11; i++) {
		Insert(l, i, i + 1);
	}
	Print(l);

	Delete(l, 11);
	Print(l);

	return 0;
}

2.循环单链表

在单链表的基础上,使得表尾部的元素的next指针指向表头。

在实现单链表时,如果在表头加上哑节点,实现起来就会比较容易,因为这样表头的地址就是始终不变的。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct Lnode {
	int value;
	struct Lnode* next;
}Lnode;

typedef struct List {
	Lnode* head;
	int numofele;
}List;

List* CreatList() {
	List* ret = (List*)malloc(sizeof(List));
	if (ret == NULL) {
		perror("malloc:");
		return NULL;
	}
	ret->head = (Lnode*)malloc(sizeof(Lnode));
	if (ret->head == NULL) {
		perror("malloc:");
		return NULL;
	}
	ret->head->next = ret->head;
	ret->numofele = 0;
	return ret;
}

void DestroyList(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	Lnode* tmp = l->head->next;
	while (tmp != l->head) {
		Lnode* p = tmp->next;
		free(tmp);
		tmp = p;
	}
	free(tmp);
	tmp = NULL;
	free(l);
	l = NULL;
}

List* ClearList(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return NULL;
	}
	l->numofele = 0;
	Lnode* tmp = l->head->next;
	l->head->next = l->head;
	while (tmp != l->head) {
		Lnode* p = tmp->next;
		free(tmp);
		tmp = p;
	}
	return l;
}

bool IsEmpty(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return false;
	}
	return l->numofele == 0;
}

int GetListLength(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return -1;
	}
	return l->numofele;
}

int GetElem(List* l, int pos) {//获得表中第pos个元素,如果pos大于表中元素个数,则循环找
	if (l == NULL) {
		printf("表不存在\n");
		return -1;
	}
	if (IsEmpty(l)) {
		printf("表为空\n");
		return -1;
	}
	if (pos < 1) {
		printf("位置不合法\n");
		return -1;
	}
	int realpos = pos % l->numofele;
	realpos = (realpos == 0 ? l->numofele : realpos);
	Lnode* tmp = l->head;
	while (realpos--) {
		tmp = tmp->next;
	}
	return tmp->value;
}

Lnode* GetElemPos(List* l, int k) {
	if (l == NULL) {
		printf("表不存在\n");
		return NULL;
	}
	if (IsEmpty(l)) {
		printf("表为空\n");
		return NULL;
	}
	Lnode* tmp = l->head->next;
	while (tmp != l->head) {
		if (tmp->value == k)
			return tmp;
		tmp = tmp->next;
	}
	printf("元素 %d 不存在\n", k);
	return NULL;
}

Lnode* GetPre(List* l, int k) {
	if (l == NULL) {
		printf("表不存在\n");
		return NULL;
	}
	Lnode* tmp = l->head;
	while (tmp->next != l->head) {
		if (tmp->next->value == k)
			return tmp;
	}
	printf("元素 %d 不存在,所以它在表中没有前驱\n", k);
	return NULL;
}

//在指定结点前插
void PreInsert(List* l, Lnode* object, int k) {

	if (l == NULL) {
		printf("表为空\n");
		return;
	}
	Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
	if (tmp == NULL) {
		perror("malloc");
		return;
	}
	
	tmp->next = object->next;
	object->next = tmp;
	tmp->value = object->value;
	object->value = k;
}

//在指定节点后插
void BackInsert(List* l, Lnode* object, int k) {

	if (l == NULL) {
		printf("表为空\n");
		return;
	}
	Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
	if (tmp == NULL) {
		perror("malloc");
		return;
	}
	tmp->next = object->next;
	object->next = tmp;
	tmp->value = k;

}

//在指定位置插入
void Insert(List* l, int k, int pos) {//在这里规定插入的位置要求要小于等于元素数量+1
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (pos<1 || pos>l->numofele + 1) {
		printf("插入位置不合法\n");
		return;
	}
	Lnode* tmp = l->head;
	int count = pos - 1;
	while (count--) {
		tmp = tmp->next;
	}
	Lnode* p = (Lnode*)malloc(sizeof(Lnode));
	if (p == NULL) {
		perror("malloc:");
		return;
	}
	p->next = tmp->next;
	p->value = k;
	tmp->next = p;
	l->numofele++;
}

//删除指定结点
int ObjectDelete(List* l, Lnode* object) {

	int ret = object->value;

	//循环链表中每个结点都有后继,所以只需要考虑后继节点是否为头节点
	Lnode* tmp = object->next;
	if (tmp == l->head) {
		l->head = object;
	}
	else {
		object->value = tmp->value;
	}
	object->next = tmp->next;
	free(tmp);
	tmp = NULL;

	return ret;

}

//删除指定位置的结点,规定i大于1小于等于表中元素个数
int Delete(List* l, int i) {
	if (l == NULL) {
		printf("表不存在\n");
		return -1;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法删除\n");
		return -1;
	}
	if (i<1 || i>l->numofele) {
		printf("位置不合法\n");
		return -1;
	}

	Lnode* tmp = l->head;
	i--;
	while (i--) {
		tmp = tmp->next;
	}
	Lnode* p = tmp->next;
	int ret = p->value;
	tmp->next = p->next;
	free(p);
	p = NULL;
	return ret;
}

void Print(List* l, Lnode* begin) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法打印\n");
		return;
	}
	Lnode* tmp = begin->next;
	if (begin != l->head) {
		printf("%d ", begin->value);
	}
	while (tmp != begin) {
		if (tmp != l->head) {
			printf("%d ", tmp->value);
		}
		tmp = tmp->next;
	}
	printf("元素数量 = %d\n", l->numofele);
}

int main() {

	List* l = CreatList();
	Print(l, l->head);

	for (int i = 0; i < 11; i++) {
		Insert(l, i, i + 1);
	}
	Print(l, l->head);
	
	Delete(l, 1);
	Print(l, GetElemPos(l, 10));

	return 0;
}

3.循环双链表

在双链表的基础上,使表头能指向表尾,使表尾能指向表头。

最好在表头和表尾都加上哑节点,这样不论是增加还是删除,都不会改变表头和表尾的地址。因为在增删表头或表尾元素时,必须要记住表尾或是表头的地址,如果不适用哑节点的话,就需要两个专门的变量来存放表头和表尾的地址。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

//循环双链表如果使用一个头节点和尾节点将会非常好实现

typedef struct Lnode {
	int value;
	struct Lnode* next;
	struct Lnode* previous;
}Lnode;

typedef struct List {
	Lnode* head;
	Lnode* tail;
	int numofele;
}List;

List* CreatList() {
	List* ret = (List*)malloc(sizeof(List));
	if (ret == NULL) {
		perror("malloc");
		return NULL;
	}
	ret->numofele = 0;
	ret->head = (Lnode*)malloc(sizeof(Lnode));
	if (ret->head == NULL) {
		perror("malloc");
		return NULL;
	}
	ret->tail = (Lnode*)malloc(sizeof(Lnode));
	if (ret->tail == NULL) {
		perror("malloc");
		return NULL;
	}
	//为了测试删除等操作的边界情况,例如删除最后一个结点,所以这里不使用尾节点
	//使用尾节点可以让操作更方便
	ret->head->next = ret->head;
	ret->head->previous = ret->head;
	ret->tail->next = ret->head;
	ret->tail->previous = ret->head;
	return ret;
}

void DestroyList(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	Lnode* tmp = l->head->next;
	while (tmp != l->head) {
		Lnode* p = tmp->next;
		free(tmp);
		tmp = p;
	}
	free(l->head);
	free(l);
	l = NULL;
}

List* ClearList(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return NULL;
	}
	Lnode* tmp = l->head->next;
	while (tmp != l->tail) {
		Lnode* p = tmp->next;
		free(tmp);
		tmp = p;
	}
	l->head->next = l->tail;
	l->tail->previous = l->head;
	l->numofele = 0;
	return l;
}

bool IsEmpty(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return false;
	}
	return l->numofele == 0;
}

int GetListLength(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return -1;
	}
	return l->numofele;
}

int GetElem(List* l, int pos) {//获得表中第pos个元素,在循环链表中,不限制pos大小,可以循环找
	if (l == NULL) {
		printf("表不存在\n");
		return -1;
	}
	if (IsEmpty(l)) {
		printf("表为空\n");
		return -1;
	}
	if (pos < 1) {
		printf("输入位置不合法\n");
		return -1;
	}
	int count = pos % l->numofele;
	count = (count == 0 ? l->numofele : count);
	Lnode* tmp = l->head;
	while (count--) {
		tmp = tmp->next;
	}
	return tmp->value;
}

Lnode* GetElemPos(List* l, int k) {
	if (l == NULL) {
		printf("表不存在\n");
		return NULL;
	}
	if (IsEmpty(l)) {
		printf("表为空\n");
		return NULL;
	}
	Lnode* tmp = l->head->next;
	while (tmp != l->tail) {
		if (tmp->value == k)
			return tmp;
		tmp = tmp->next;
	}
	printf("元素 %d 不存在\n", k);
	return NULL;
}

Lnode* GetPre(List* l, int k) {
	if (l == NULL) {
		printf("表不存在\n");
		return NULL;
	}
	if (IsEmpty(l)) {
		printf("表为空\n");
		return NULL;
	}
	Lnode* tmp = l->head;
	while (tmp->next != l->tail) {
		if (tmp->next->value == k)
			return tmp;
		tmp = tmp->next;
	}
	printf("元素 %d 不存在,所以没有前驱\n", k);
	return NULL;
}

//在指定结点前插
void PreInsert(List* l, Lnode* object, int k) {
	if (l == NULL) {
		printf("表为空\n");
		return;
	}
	Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
	if (tmp == NULL) {
		perror("malloc");
		return;
	}
	Lnode* pre = object->previous;
	tmp->next = pre->next;
	tmp->previous = pre;
	pre->next = tmp;
	object->previous = tmp;
	tmp->value = k;
}

//指定结点后插
void BackInsert(List* l, Lnode* object, int k) {

	if (l == NULL) {
		printf("表为空\n");
		return;
	}
	Lnode* tmp = (Lnode*)malloc(sizeof(Lnode));
	if (tmp == NULL) {
		perror("malloc");
		return;
	}
	tmp->next = object->next;
	tmp->previous = object;
	tmp->next->previous = tmp;
	object->next = tmp;
	tmp->value = k;
}

//在指定位置插入
void Insert(List* l, int k, int pos) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (pos<1 || pos>l->numofele + 1) {
		printf("插入位置不合法\n");
		return;
	}
	int count = pos - 1;
	Lnode* tmp = l->head;
	while (count--) {
		tmp = tmp->next;
	}
	Lnode* p = (Lnode*)malloc(sizeof(Lnode));
	if (p == NULL) {
		perror("malloc");
		return;
	}
	p->value = k;
	p->next = tmp->next;
	p->previous = tmp;
	p->next->previous = p;
	tmp->next = p;
	l->numofele++;
}

//删除指定结点
int ObjectDelete(List* l, Lnode* object) {

	int ret = object->value;

	Lnode* pre = object->previous;
	pre->next = object->next;
	object->next->previous = pre;
	free(object);
	object = NULL;

	return ret;

}

//删除指定位置的结点
int Delete(List* l, int i) {
	if (l == NULL) {
		printf("表不存在\n");
		return -1;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法删除\n");
		return -1;
	}
	
	Lnode* tmp = l->head;
	while (i--) {
		tmp = tmp->next;
	}
	int ret = tmp->value;

	Lnode* pre = tmp->previous;
	pre->next = tmp->next;
	tmp->next->previous = pre;
	free(tmp);
	tmp = NULL;

	return ret;
}

void Print(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法打印\n");
		return;
	}
	Lnode* tmp = l->head->next;
	while (tmp != l->head) {
		printf("%d ", tmp->value);
		tmp = tmp->next;
	}
	printf("表中元素数量为 = %d\n", l->numofele);
}

void SetPosPrint(List* l, int pos) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法打印\n");
		return;
	}
	if (pos<1 || pos>l->numofele) {
		printf("输入位置不合法\n");
		return;
	}
	Lnode* begin = l->head;
	while (pos--) {
		begin = begin->next;
	}
	Lnode* tmp = begin->next;
	while (tmp != begin) {
		if (tmp != l->head && tmp != l->tail) {
			printf("%d ", tmp->value);
		}
		tmp = tmp->next;
	}
	printf("%d    表中元素数量为 = %d\n", begin->value, l->numofele);
}

void ReversePrint(List* l) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法打印\n");
		return;
	}
	Lnode* tmp = l->head->previous;
	while (tmp != l->head) {
		printf("%d ", tmp->value);
		tmp = tmp->previous;
	}
	printf("表中元素数量为 = %d\n", l->numofele);
}

void SetPosReversePrint(List* l, int pos) {
	if (l == NULL) {
		printf("表不存在\n");
		return;
	}
	if (IsEmpty(l)) {
		printf("表为空,无法打印\n");
		return;
	}
	if (pos<1 || pos>l->numofele) {
		printf("输入位置不合法\n");
		return;
	}
	Lnode* begin = l->head;
	while (pos--) {
		begin = begin->next;
	}
	Lnode* tmp = begin->previous;
	while (tmp != begin) {
		if (tmp != l->head && tmp != l->tail) {
			printf("%d ", tmp->value);
		}
		tmp = tmp->previous;
	}
	printf("%d    表中元素数量为 = %d\n", begin->value, l->numofele);
}

int main() {

	List* l = CreatList();
	for (int i = 0; i <= 10; i++) {
		Insert(l, i, i + 1);
	}
	Print(l);
	ReversePrint(l);
	

	Delete(l, 11);
	Print(l);
	ReversePrint(l);

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值