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;
}