数据结构笔记

18、双向链表

单链表中每个结点除了存储自身数据之后,还存储了下一个结点的地址,因此可以轻松访问下一个结点,以及后面的后继结点,但是如果想访问前面的结点就不行了,再也回不去了。例如删除结点p时,要先找到它的前一个结点q,然后才能删掉p结点,单向链表只能往后走,不能向前走。双向链表可以解决此问题。
在这里插入图片描述
1、双向链表初始化

typedef struct _DboubleLinkNode{
	int data;
	struct _DboubleLinkNode *next;//下一个节点
	struct _DboubleLinkNode *prev;//上一个节点
}DbLinkNode,DbLinkList;

bool DbInit_List(DbLinkList* &L){
	L= new DbLinkList; //生成新节点作为头节点,用头指针L指向头节点
	if(!L)return false;
	L->next = NULL;
	L->prev = NULL;
	L->data = -1;
	return true;
}

2、前插法

bool DbListInsert_front(DbLinkList* &L,DbLinkList* node){
	if(!L || !node)return false;
	//只有头节点
	if(L->next =NULL){
		node->next=L->next;
		node->prev = L;
		L->next = node;
	}else{
		L->next->prev = node;
		node->next=L->next;
		node->prev = L;
		L->next = node;
	}
	return true;
}

在这里插入图片描述

3、尾插法

bool DbListInsert_back(DbLinkList* &L,DbLinkNode *node){
	DbLinkNode *last = NULL;
	if(!L || !node)return false;
	
	last =L;
	while(last->next)last = last->next;//寻找最后一个节点
	
	node->next = NULL;
	last->next = node;
	node->prev = last;

	return true;
}

在这里插入图片描述

4、指定位置插入
在这里插入图片描述

bool DbLink_Insert(DbLinkList* &L,int i,int &e){ //在第i个位置插入e
	if(!L ||!L->next)return false;
	if(i<1)return false;

	int j=0;
	DbLinkList *p,*s;//p为当前节点,s为要插入的节点
	p=L;
	while(p && j<i){//查找位置为i的节点,p指向该节点
		p=p->next;
		j++;
	}
	if(!p || j!=i){ 
		cout << "不存在节点:" << i << endl;
		return false;
	}
	cout<<"p:"<<p<<endl;

	s =new DbLinkNode;
	
	s->data = e;

	s->next = p;
	s->prev = p->prev;

	p->prev->next = s;
	p->prev = s;
	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;
	index =1;
	while(p && index<i){
	p = p->next;
	index++;
	}
	if(!p||index>i)return false;  // i值不合法,i>n或者i<=0
	e = p->date;
	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;
	while(p && index<i){//链表向后扫描,直到p指向第i个元素或p为空
		p=p->next;
		index++;
	}
	p->prev->next = p->next;
	p->next->prev=p->prev;
	
	delete p;
	return true;
}

7、双向链表的销毁

void DbLink_Destory(DbLinkList* &L){
	DbLinkList*p=L;
	cout<<"销毁链表!"<<endl;
	while(p){
		L=L->next;
		cout<<"删除元素"<<p->data<<endl;
		delete L;
		p=L;
	}
}

双向链表的遍历输出

void DbLink_Print(DbLinkList* &L){
	DbLinkNode *p = NULL;
	if(!L){
		cout << "链表为空!" << endl;
		return;
	}
	p=L;
	
	while(p->next){
		cout<<p->next->data<<"\t";
		p=p->next;
	}

	//逆向打印    //这个时候的p在最后一个节点的位置
	cout<<endl<<"逆向打印"<<endl;
	while(p&&p!=L){
		cout<<p->data<<"\t";
		p=p->prev;
	}
	cout<<endl;
}

main函数

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

	//初始化一个双向链表
	DbList_Init(L);

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

	//3、使用尾插法插入数据
	int n;
	cout << "尾插法创建链表" << endl;
	cout << "请输入元素个数n:";
	cin >> n;
	cout << "\n请依次输入n个元素:" << endl;
	
	while (n > 0) {
		s = new DbLinkNode;
		
		cin >> s->data;
		DbListInsert_back(L, s);
		n--;
	}
		//4、任意位置插入
	for (int j = 0; j < 3; j++) {
		int i, x;
		cout << "请输入插入位置和元素:";
		cin >> i;
		cin >> x;

		if (DbLink_Insert(L, i, x)) {
			cout << "插入成功!\n";
		}
		else {
			cout << "插入失败!\n";
		}

		DbLink_Print(L);
	}

	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值