数据结构学习

本文介绍了双向链表的概念,包括其与单向链表的区别、特点和优势。详细阐述了双向链表节点的定义,如包含的数据域和指针,并提供了初始化、创建节点、插入(头插、尾插)、删除(头删、尾删、按值删)及查找、更改节点值等操作的C语言实现代码。此外,还讨论了双向链表在空间开销和遍历灵活性上的特点。
摘要由CSDN通过智能技术生成

双链表

定义:

双向链表(Doubly Linked List)是一种常见的链表数据结构,它与普通的单向链表相比,每个节点除了有一个指向下一个节点的指针(通常称为next指针)外,还有一个指向前一个节点的指针(通常称为prev指针)。这使得在双向链表中,我们可以从任一端(头部或尾部)开始遍历和操作链表,而不像单向链表只能从头部开始。

双向链表节点(DNode)的定义通常包含两个指针(nextprev)以及一个数据域(用来存储节点的值)。

特点:

  1. 双向遍历:与单向链表只能从头到尾遍历不同,双向链表可以从头到尾或从尾到头进行遍历。这是因为每个节点都有一个指向前一个节点的指针。

  2. 插入和删除效率高:在双向链表中,如果已经知道要插入或删除节点的位置,操作的时间复杂度为O(1)。因为在双向链表中,可以通过修改指针来完成插入和删除操作,而不需要像单向链表那样找到前一个节点。

  3. 空间开销:相比较单向链表,双向链表在每个节点多了一个指向前一个节点的指针,因此会稍微增加一些空间开销。

  4. 遍历方向灵活:双向链表可以支持双向遍历,这在某些场景下非常方便。例如,当需要在链表末尾添加节点或从链表末尾删除节点时,单向链表需要从头遍历整个链表来找到末尾节点,而双向链表可以直接从尾部开始操作。

  5. 逆序操作:双向链表可以较方便地实现逆序操作,例如逆序打印链表。

节点描述:

typedef struct DNode {
	int val;
	DNode* next;
	DNode* pre;
}DNode;

双链表描述:

typedef struct DList {
	DNode* head;
}DList,*PDList;

初始化:

void InitDList(PDList plist) {
	plist->head = NULL;
}

创建节点:

DNode* CreatDNode(int val) {
	DNode* p = (DNode*)malloc(sizeof(DNode));
	p->val = val;
	return p;
}

头插法:

void InsertHead(PDList plist,int val) {
	assert(plist != NULL);
	DNode* p = CreatDNode(val);
	if (plist->head != NULL) {
		DNode* curr = plist->head;
		curr->pre = p;
		p->next = curr;
		plist->head = p;
	}
	else
	{
		plist->head = p;
		p->next = NULL;
		p->pre = NULL;
	}
}

尾插法:

void InsertTail(PDList plist, int val) {
	assert(plist != NULL);
	DNode* p = CreatDNode(val);
	if (plist->head != NULL) {
		DNode* curr = plist->head;
		while (curr->next!= NULL) {
			curr = curr->next;
		}
		curr->next = p;
		p->pre = curr;
		p->next = NULL;
	}
	else {
		plist->head = p;
		p->pre = NULL;
		p->next = NULL;
	}
}

头删:

void DeleteHead(PDList plist) {
	assert(plist != NULL && plist->head != NULL);
	if (plist->head->next != NULL) {
		DNode* curr = plist->head;
		plist->head = curr->next;
		curr->next->pre = NULL;
		free(curr);
	}
	else {
		free(plist->head);
		plist->head = NULL;
	}
}

尾删:

void DeleteTail(PDList plist) {
	assert(plist != NULL && plist->head != NULL);
	if (plist->head->next != NULL) {
		DNode* curr = plist->head;
		while (curr->next->next!= NULL) {
			curr = curr->next;
		}
		DNode* tail = curr->next;
		curr->next = NULL;
		free(tail);
	}
	else {
		free(plist->head);
		plist->head = NULL;
	}
}

根据值删:

void DeleteVal(PDList plist, int val) {
	assert(plist != NULL);
	DNode* curr = plist->head;

	while (curr != NULL) {
		DNode* nextNode = curr->next;

		if (curr->val == val) {
			if (curr == plist->head) {
				plist->head = curr->next;
			}

			if (curr->pre != NULL) {
				curr->pre->next = curr->next;
			}

			if (curr->next != NULL) {
				curr->next->pre = curr->pre;
			}

			free(curr);
		}

		curr = nextNode;
	}
}

查找节点:

DNode*  SearchVal(PDList plist, int val) {
	assert(plist != NULL);
	DNode* curr = plist->head;
	while (curr->next != NULL) {
		if (curr->val == val) {
			return curr;
		}
		curr = curr->next;
	}
	return NULL;
}

更换节点的值:

void ChangeVal(PDList plist, int val,int newval) {
	assert(plist != NULL);
	DNode* curr = plist->head;
	while (curr->next != NULL) {
		if (curr->val == val) {
			curr->val = newval;
		}
		curr = curr->next;
	}
}

展示双链表:

void show(PDList plist) {
	assert(plist!= NULL);
	DNode* curr = plist->head;
	while (curr!= NULL) {
		printf("%d ", curr->val);
		curr = curr->next;
	}

}

完整代码(含测试用例)

#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
typedef struct DNode {
	int val;
	DNode* next;
	DNode* pre;
}DNode;
typedef struct DList {
	DNode* head;
}DList,*PDList;
void InitDList(PDList plist) {
	plist->head = NULL;
}
DNode* CreatDNode(int val) {
	DNode* p = (DNode*)malloc(sizeof(DNode));
	p->val = val;
	return p;
}
void InsertHead(PDList plist,int val) {
	assert(plist != NULL);
	DNode* p = CreatDNode(val);
	if (plist->head != NULL) {
		DNode* curr = plist->head;
		curr->pre = p;
		p->next = curr;
		plist->head = p;
	}
	else
	{
		plist->head = p;
		p->next = NULL;
		p->pre = NULL;
	}
}
void InsertTail(PDList plist, int val) {
	assert(plist != NULL);
	DNode* p = CreatDNode(val);
	if (plist->head != NULL) {
		DNode* curr = plist->head;
		while (curr->next!= NULL) {
			curr = curr->next;
		}
		curr->next = p;
		p->pre = curr;
		p->next = NULL;
	}
	else {
		plist->head = p;
		p->pre = NULL;
		p->next = NULL;
	}
}
void DeleteHead(PDList plist) {
	assert(plist != NULL && plist->head != NULL);
	if (plist->head->next != NULL) {
		DNode* curr = plist->head;
		plist->head = curr->next;
		curr->next->pre = NULL;
		free(curr);
	}
	else {
		free(plist->head);
		plist->head = NULL;
	}
}
void DeleteTail(PDList plist) {
	assert(plist != NULL && plist->head != NULL);
	if (plist->head->next != NULL) {
		DNode* curr = plist->head;
		while (curr->next->next!= NULL) {
			curr = curr->next;
		}
		DNode* tail = curr->next;
		curr->next = NULL;
		free(tail);
	}
	else {
		free(plist->head);
		plist->head = NULL;
	}
}
void DeleteVal(PDList plist, int val) {
	assert(plist != NULL);
	DNode* curr = plist->head;

	while (curr != NULL) {
		DNode* nextNode = curr->next;

		if (curr->val == val) {
			if (curr == plist->head) {
				plist->head = curr->next;
			}

			if (curr->pre != NULL) {
				curr->pre->next = curr->next;
			}

			if (curr->next != NULL) {
				curr->next->pre = curr->pre;
			}

			free(curr);
		}

		curr = nextNode;
	}
}
DNode*  SearchVal(PDList plist, int val) {
	assert(plist != NULL);
	DNode* curr = plist->head;
	while (curr->next != NULL) {
		if (curr->val == val) {
			return curr;
		}
		curr = curr->next;
	}
	return NULL;
}
void ChangeVal(PDList plist, int val,int newval) {
	assert(plist != NULL);
	DNode* curr = plist->head;
	while (curr->next != NULL) {
		if (curr->val == val) {
			curr->val = newval;
		}
		curr = curr->next;
	}
}
void show(PDList plist) {
	assert(plist!= NULL);
	DNode* curr = plist->head;
	while (curr!= NULL) {
		printf("%d ", curr->val);
		curr = curr->next;
	}

}
int main() {
	DList plist;
	InitDList(&plist);
	for (int i = 0; i < 4; i++) {
		InsertHead(&plist, i);
		InsertTail(&plist, i);
	}
	DeleteHead(&plist);
	DeleteTail(&plist);
	DeleteVal(&plist, 0);
	ChangeVal(&plist, 1, 3);
	show(&plist);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值