数据结构与算法 双向链表

数据结构与算法 双向链表

双向链表

对于双向链表来说,它无非就是在单链表的基础上,在链表中多增加了一个指针域,用来存储上一个节点的地址。 单链表没有上一个节点的地址,所以无法访问它,只能访问它下一个节点,而双向链表因其比单链表多一个指针域用来存储上一个节点的地址,所以可以访问,这就是双向链表。

1.初始化双向链表

双向链表初始化只是在单链表的基础上多增加了一个指针域,所以变化不大,初始化这个指针就可以了。

//结构体定义链表
typedef struct _DoubleLinkNode {
	int data;   //数据域(存储数据)
	struct _DoubleLinkNode* next; //指针节点,指向(存储)下个链表节点的地址
	struct _DoubleLinkNode* prev; //指向上一个节点地址
}DLinkNode, DLinkList; //链表节点、链表

//初始化链表,定义头节点
bool DInitList(DLinkList*& L) { //构造一个空的单链表 L
	L = new DLinkNode;   //创建新结点作为头结点,用头指针L指向头结点

	if (!L) {
		cout << "初始化链表失败!" << endl;
		return false;//生成结点失败
	}

	L->next = NULL; //头结点的指针域置空(指向下一个节点)
	L->prev = NULL; //头结点的指针域置空(指向上一个节点)
	L->data = -1;   //链表数据设置为-1
	cout << "初始化链表成功!" << endl;
	return true;
}

2.前插法

(在不是空链表的情况下L为头节点)L->next为头节点的下一个节点的地址,L->next->prev为头(本)节点的地址,在单链表的基础上,多了一个逆指向。

//前插法 
bool DbListInsert_front(DbLinkList* &L, DbLinkNode *node){ 
	if(!L || !node) return false; //判断是否为空

	if(L->next==NULL){		//判断是否为头节点 
		node->next = NULL;		//将新节点next(指向下个节点指针)指针设为空
		node->prev = L;			//将新节点prev指针指向头节点 
		L->next=node;			//头节点next指针指向新节点
	}else {					//不是头节点的情况
		L->next->prev=node;		//第二个节点的 prev 指向新节点 
		node->next = L->next;	//新节点 next 指针指向第二个节点 
		node->prev=L;			//新节点 prev 指针指向头节点 
		L->next=node;			//头节点 next 指针指向新节点,完成插入 
	}

	return true;
}

3.尾插法

与单链表大体相同

//尾插法 
bool DbListInsert_back(DbLinkList* &L, DbLinkNode *node){
	DbLinkNode *last = NULL; 

	if(!L || !node) return false; //合法性检查

	last = L;   //last指针指向头节点

	while(last->next) last = last->next; //找出最后一个节点

	node->next = NULL;    //将新节点next指针设置为空
	last->next = node;	  //将最后一个节点的next指向新节点地址
	node->prev = last;	  //将新节点prev指针指向最后一个节点的地址

	return true;
}

4.任意位置插入

//指定位置插入 
bool DbLink_Insert(DbLinkList* &L, int i, int &e){ 
	if(!L||!L->next) return false; //链表不能为空

	if(i<1) return false; //i不能小于0

	int j =0; 
	DbLinkList *p, *s; 
	p = L; //指针p指向头节点

	while(p && j<i){//查找位置为 i 的结点,p 指向该结点 
		p = p->next;  //找出该位置(位置为i)节点
		j++; 
	}

	if(!p || j!=i){ 
		cout<<"不存在节点:"<<i<<endl; 
		return false; 
	}

	s = new DbLinkNode; //生成新节点 
	s->data = e;	    //插入数据赋值给新节点数据域
	s->next = p;		//将新节点next指针指向i位置节点地址
	s->prev = p->prev;  //将新节点prev指针指向i节点的上一个节点
	p->prev->next = s;  //将i节点的上一个节点next指针指向新节点
	p->prev = s;		//将i节点prev指针指向新节点地址

	return true;
}

5.双向链表按位置取值

//双向链表的取值 
bool DbLink_GetElem(DbLinkList*& L, int i, int& e) { 
	//在带头结点的双向链表 L 中查找第 i 个元素 
	//用 e 记录 L 中第 i 个数据元素的值 
	int index; 
	DbLinkList *p; 

	if(!L || !L->next) return false; //合法性检查

	p = L->next; //将p指针指向第一个节点
	index = 1; 

	while(p && index<i){//顺链表向后扫描,直到 p 指向第 i 个元素或 p 为空
		p = p->next; //p 指向下一个结点 
		index++; //计数器 index 相应加 1 
	}

	if(!p || index>i){ 
		return false; //i 值不合法,i>n 或 i<=0 
	}

	e=p->data; //数据赋值
	return true; 
}

6.任意位置删除

//任意位置删除 
bool DbLink_Delete(DbLinkList*& L, int i) {//双向链表的删除
	DbLinkList* p;
	int index = 0;

	if (!L || !L->next) {
		cout << "双向链表为空!" << endl;
		return false;
	}

	if (i < 1) return false; //不能删除头节点 

	p = L;  //指针p指向头节点

	while (p && index < i) {//循环查找i节点
		p = p->next;
		index++;
	}

	if (!p) { //当节点不存在时,返回失败 
		return false;
	}

	p->prev->next = p->next; //将i节点前节点的next指针指向i节点下一个节点地址

	if (p->next) {
		p->next->prev = p->prev; //改变删除节点后节点的 prev 指针域 
	}

	delete p; //释放被删除结点的空间 
	return true;
}

7.销毁链表

//双向链表的销毁
void DbLink_Destroy(DbLinkList*& L) { //定义临时节点 p 指向头节点 
	DbLinkList *p = L; 
	
	while(p){ 
		L=L->next;//L 指向下一个节点 
		cout<<"删除元素: "<<p->data<<endl; 
		delete p; //删除当前节点 
		p = L; //p 移向下一个节点 
	} 

	cout << "链表已销毁!" << endl;
}

8.打印链表

//双向链表的遍历输出 
void DbLink_Print(DbLinkList* &L ){ 
	DbLinkNode *p = NULL;

	if(!L){ 
		cout<<"链表为空."<<endl; 
		return ; 
	}

	p = L; //指针p指向头节点

	while(p->next){  //循环打印数据
		cout<<p->next->data<<"\t"; 
		p = p->next; 
	}

	//逆向打印 
	cout<<endl<<"逆向打印"<<endl; 
	while(p){ 
		cout<<p->data<<"\t"; 
		p = p->prev; 
	}
	cout<<endl; 
}

完整代码

#include <iostream>
#include <string>
#include <stdlib.h>

using namespace std;

//结构体定义链表
typedef struct _DoubleLinkNode {
	int data;   //数据域(存储数据)
	struct _DoubleLinkNode* next; //指针节点,指向(存储)下个链表节点的地址
	struct _DoubleLinkNode* prev; //指向上一个节点地址
}DbLinkNode, DbLinkList; //链表节点、链表

//初始化链表,定义头节点
bool DbInitList(DbLinkList*& L) { //构造一个空的单链表 L
	L = new DbLinkNode;   //创建新结点作为头结点,用头指针L指向头结点

	if (!L) {
		cout << "初始化链表失败!" << endl;
		return false;//生成结点失败
	}

	L->next = NULL; //头结点的指针域置空(指向下一个节点)
	L->prev = NULL; //头结点的指针域置空(指向上一个节点)
	L->data = -1;   //链表数据设置为-1
	cout << "初始化链表成功!" << endl;
	return true;
}

//前插法 
bool DbListInsert_front(DbLinkList* &L, DbLinkNode *node){ 
	if(!L || !node) return false; //判断是否为空

	if(L->next==NULL){		//判断是否为头节点 
		node->next = NULL;		//将新节点next(指向下个节点指针)指针设为空
		node->prev = L;			//将新节点prev指针指向头节点 
		L->next=node;			//头节点next指针指向新节点
	}else {					//不是头节点的情况
		L->next->prev=node;		//第二个节点的 prev 指向新节点 
		node->next = L->next;	//新节点 next 指针指向第二个节点 
		node->prev=L;			//新节点 prev 指针指向头节点 
		L->next=node;			//头节点 next 指针指向新节点,完成插入 
	}

	return true;
}

//尾插法 
bool DbListInsert_back(DbLinkList* &L, DbLinkNode *node){
	DbLinkNode *last = NULL; 

	if(!L || !node) return false; //合法性检查

	last = L;   //last指针指向头节点

	while(last->next) last = last->next; //找出最后一个节点

	node->next = NULL;    //将新节点next指针设置为空
	last->next = node;	  //将最后一个节点的next指向新节点地址
	node->prev = last;	  //将新节点prev指针指向最后一个节点的地址

	return true;
}

//指定位置插入 
bool DbLink_Insert(DbLinkList* &L, int i, int &e){ 
	if(!L||!L->next) return false; //链表不能为空

	if(i<1) return false; //i不能小于0

	int j =0; 
	DbLinkList *p, *s; 
	p = L; //指针p指向头节点

	while(p && j<i){//查找位置为 i 的结点,p 指向该结点 
		p = p->next;  //找出该位置(位置为i)节点
		j++; 
	}

	if(!p || j!=i){ 
		cout<<"不存在节点:"<<i<<endl; 
		return false; 
	}

	s = new DbLinkNode; //生成新节点 
	s->data = e;	    //插入数据赋值给新节点数据域
	s->next = p;		//将新节点next指针指向i位置节点地址
	s->prev = p->prev;  //将新节点prev指针指向i节点的上一个节点
	p->prev->next = s;  //将i节点的上一个节点next指针指向新节点
	p->prev = s;		//将i节点prev指针指向新节点地址

	return true;
}

//双向链表的取值 
bool DbLink_GetElem(DbLinkList*& L, int i, int& e) { 
	//在带头结点的双向链表 L 中查找第 i 个元素 
	//用 e 记录 L 中第 i 个数据元素的值 
	int index; 
	DbLinkList *p; 

	if(!L || !L->next) return false; //合法性检查

	p = L->next; //将p指针指向第一个节点
	index = 1; 

	while(p && index<i){//顺链表向后扫描,直到 p 指向第 i 个元素或 p 为空
		p = p->next; //p 指向下一个结点 
		index++; //计数器 index 相应加 1 
	}

	if(!p || index>i){ 
		return false; //i 值不合法,i>n 或 i<=0 
	}

	e=p->data; //数据赋值
	return true; 
}

//任意位置删除 
bool DbLink_Delete(DbLinkList*& L, int i) {//双向链表的删除
	DbLinkList* p;
	int index = 0;

	if (!L || !L->next) {
		cout << "双向链表为空!" << endl;
		return false;
	}

	if (i < 1) return false; //不能删除头节点 

	p = L;  //指针p指向头节点

	while (p && index < i) {//循环查找i节点
		p = p->next;
		index++;
	}

	if (!p) { //当节点不存在时,返回失败 
		return false;
	}

	p->prev->next = p->next; //将i节点前节点的next指针指向i节点下一个节点地址

	if (p->next) {
		p->next->prev = p->prev; //改变删除节点后节点的 prev 指针域 
	}

	delete p; //释放被删除结点的空间 
	return true;
}

//双向链表的销毁
void DbLink_Destroy(DbLinkList*& L) { //定义临时节点 p 指向头节点 
	DbLinkList *p = L; 
	
	while(p){ 
		L=L->next;//L 指向下一个节点 
		cout<<"删除元素: "<<p->data<<endl; 
		delete p; //删除当前节点 
		p = L; //p 移向下一个节点 
	} 

	cout << "链表已销毁!" << endl;
}

//双向链表的遍历输出 
void DbLink_Print(DbLinkList* &L ){ 
	DbLinkNode *p = NULL;

	if(!L){ 
		cout<<"链表为空."<<endl; 
		return ; 
	}

	p = L; //指针p指向头节点

	while(p->next){  //循环打印数据
		cout<<p->next->data<<"\t"; 
		p = p->next; 
	}

	//逆向打印 
	cout<<endl<<"逆向打印"<<endl; 
	while(p){ 
		cout<<p->data<<"\t"; 
		p = p->prev; 
	}
	cout<<endl; 
}



int main(void) {
	DbLinkList* L = NULL; 
	DbLinkNode* s = NULL; 

	//1. 初始化一个空的双向链表 
	DbInitList(L);
	
	//2. 使用前插法插入数据 
	int n; 
	cout<<"前插法创建双向链表"<<endl; 
	std::cout<<"请输入元素个数 n:"; 
	cin>>n;
	cout << "\n 请依次输入 n 个元素:" << endl; 
	while (n > 0) {
		s = new DbLinkNode; //生成新节点 s 
		cin>>s->data; 
		DbListInsert_front(L, s);
		n--; 
	}

	//3. 使用尾插法插入数据 
	cout<<"尾插法创建双向链表"<<endl; 
	std::cout<<"请输入元素个数 n:"; 
	cin>>n; 
	cout<<"\n 请依次输入 n 个元素:" <<endl; 
	while(n>0){ 
		s = new DbLinkNode; //生成新节点 s 
		cin>>s->data; 
		DbListInsert_back(L, s); 
		n--; 
	}

	//4. 双向链表的输出 
	DbLink_Print(L); //5. 任意位置插入元素 
	for(int j=0; j<3; j++){ 
		int i, x; 
		cout << "请输入插入的位置和元素(用空格隔开):"; 
		cin >> i; 
		cin >> x; 
		if(DbLink_Insert(L, i, x)){ 
			cout << "插入成功.\n\n"; 
		}else{ 
			cout << "插入失败!\n\n"; 
		}DbLink_Print(L); 
	}
	
	//6. 双向链表根据位置获取元素 
	int element = 0; 
	if(DbLink_GetElem(L, 2, element)){ 
		cout<<"获取第二个元素成功, 值:"<<element<<endl;
	}else { 
		cout << "获取第二个元素失败!" << endl;
	}

	//7. 双向链表删除元素 
	if(DbLink_Delete(L, 2)){ 
		cout<<"删除第 2 个元素成功!"<<endl; 
		DbLink_Print(L); 
	}else { 
		cout<<"删除第 2 个元素失败!"<<endl; 
	}if(DbLink_Delete(L, 1)){ 
		cout<<"删除第 1 个元素成功!"<<endl; 
		DbLink_Print(L); 
	}else { 
		cout<<"删除第 1 个元素失败!"<<endl; 
	}
	
	//8. 销毁双向链表 
	DbLink_Destroy(L); 
	system("pause"); 
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package 单双向链表; /** * 单向链表增删改查操作 * */ public class LinkTest { public static void main(String[] args) { Link l=new Link(); l.addNode("A"); l.addNode("B"); l.addNode("C"); l.addNode("D"); l.addNode("E"); l.printNode(); System.out.println("\n是否包含D:"+l.contains("D")); System.out.println("==========删除之前的内容=========="); l.printNode(); System.out.println("\n==========删除之后的内容=========="); l.deleteNode("A"); l.printNode(); } } class Link{//链表的完成类 class Node{//保存每个节点 private String data;//节点内容 private Node next;//下一个节点 public Node(String data){ this.data=data; } public void add(Node newNode) {//将节点加入到合适的位置 if(this.next==null){ this.next=newNode; }else{ this.next.add(newNode); } } public void print() {//输出节点的内容 System.out.print(this.data+"\t"); if(this.next!=null){ this.next.print();//递归调用输出 } } public boolean search(String data){//内部搜索的方法 if(data.equals(this.data)){ return true; }else{ if(this.next!=null){//向下继续判断 return this.next.search(data); }else{ return false; } } } public void delete(Node previous, String data) { if(data.equals(this.data)){//找到了匹配的节点 previous.next=this.next;//空出当前的节点 }else{ if(this.next!=null){ this.next.delete(this, data);//继续查找 } } } } private Node root;//链表中的根节点 public void addNode(String data){//增加节点 Node newNode=new Node(data); if(root==null){ root=newNode; }else{ root.add(newNode); } } public void printNode(){//链表的输出 if(root!=null){ root.print(); } } public boolean contains(String name){//判断元素是否存在 return this.root.search(name); } public void deleteNode(String data){//链表删除节点 if(this.contains(data)){ if(this.root.data.equals(data)){//如果是根节点 this.root=this.root.next;//修改根节点 }else{ this.root.next.delete(root,data);//把下一个节点的前节点和要删除的节点内容一起传入 } } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值