双向链表的算法实现
单链表中每个结点除了存储自身数据之后,还存储了下一个结点的地址,因此可以轻松访问下一个结点,以及后面的后继结点,但是如果想访问前面的结点就不行了,再也回不去了。例如删除结点 p 时,要先找到它的前一个结点 q,然后才能删掉 p 结点,单向链表只能往后走,不能向前走。如果需要向前走,怎么办呢?
可以在单链表的基础上给每个元素附加两个指针域,一个存储前一个元素的地址,一个存储下一个元素的地址。这种链表称为双向链表.
其结构体定义:
typedef struct _LinkNode {
int data; //结点的数据域 struct _LinkNode *next; //下一个节点的指针域
struct _LinkNode *prev; //上一个结点的指针域
}LinkNode, LinkList; //LinkList 为指向结构体 LNode 的指针类型
双向链表的初始
//前插法 bool DbListInsert_front(DbLinkList* &L, DbLinkNode *node){ if(!L || !node) return false; //1.只有头节点 if(L->next==NULL){ typedef struct _DoubleLinkNode { int data; //结点的数据域 struct _DoubleLinkNode *next; //下一个节点的指针域 struct _DoubleLinkNode *prev; //上一个结点的指针域 }DbLinkNode, DbLinkList; //LinkList为指向结构体LNode的指针类型 bool DbInit_List(DbLinkList* &L)//构造一个空的双向链表L { L=new DbLinkNode; //生成新结点作为头结点,用头指针L指向头结点 if(!L)return false; //生成结点失败 L->next=NULL; //头结点的next指针域置空 L->prev=NULL; //头结点的指针域置空 L->data = -1; return true; } |
双向链表增加元素前插法
node->next=NULL; 11 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; while(last->next) last = last->next; node->next = NULL; last->next = node; node->prev = last; return true; } |
任意位置插入
//指定位置插入 bool DbLink_Insert(DbLinkList* &L, int i, int &e){ if(!L||!L->next) return false; if(i<1) return false; int j =0; DbLinkList *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; } |
双向链表的遍历
//双向链表的遍历输出 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; } //逆向打印 cout<<endl<<"逆向打印"<<endl; while(p){ cout<<p->data<<"\t"; p = p->prev; } cout<<endl; } |
双向链表获取元素
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指向第i个元素或p为空 p = p->next; index++; } if(!p || index>i){ return false; //i值不合法,i>n或i<=0 } e=p->data; return true; } | ||
11 | ||
双向链表删除元素
//任意位置删除 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 = p->next; index++; } if(!p){ //当节点不存在时,返回失败 return false; } p->prev->next=p->next; //改变删除结点前驱结点的next 指针域 if(p->next){ p->next->prev = p->prev; //改变删除节点后继节点的prev 指针域 } delete p; //释放被删除结点的空间 return true; | |
} | 11 |
双向链表销毁
void DbLink_Destroy(DbLinkList* &L) //双向链表的销毁 { //定义临时节点p指向头节点 DbLinkList *p = L; cout<<"销毁链表!"<<endl; while(p){ L=L->next;//L指向下一个节点 cout<<"删除元素: "<<p->data<<endl; delete p; //删除当前节点 p = L; //p 移向下一个节点 } } |
完整代码实现:
#include <iostream>
#include <Windows.h>
using namespace std;
typedef struct _DbLinkList
{
int data;//数据域
struct _DbLinkList* prev;//前驱结点
struct _DbLinkList* next;//后继结点
}DbLinkList, DbLinkNode;
bool DbLinkList_Init(DbLinkList*& L)
{
//分配头结点
L = new DbLinkNode;
if (!L)
{
return false;
}
L->next = NULL;
L->prev = NULL;
L->data = -1;
return true;
}
//头插
bool InsertDbLink_front(DbLinkList*& L, DbLinkList* node)
{
if (!L || !node)
{
return false;
}
if (L->next == NULL)
{
node->next = NULL;
node->prev = L;
L->next = node;
}
else
{
L->next->prev = node;
node->next = L->next;
node->prev = L;
L->next = node;
//L->next->prev = node; //第二个节点的 prev 指向新节点
//node->next = L->next; //新节点 next 指针指向第二个节点
//node->prev = L; //新节点 prev 指针指向头节点
//L->next = node;
}
return true;
}
//尾插
bool InsertDbLink_back(DbLinkList* &L, DbLinkNode* node)
{
if (!L || !node)
{
return false;
}
DbLinkList* q;
q = L;
while (q->next)
{
q = q->next;
}
q->next = node;
node->prev = node;
return true;
}
//任意位置插入
bool DbLink_Insert(DbLinkList*& L,int i,int &e)
{
DbLinkList* q, * s;
int j = 1;
q = L->next;
if (!L || !L->next)
{
return false;
}
while (!q || j < i)
{
q = q->next;
j++;
}
if (!q || i != j)
{
return false;
}
s = new DbLinkNode;
s->data = e;
q->prev->next = s;
s->prev = q->prev;
s->next = q;
q->prev = s;
return true;
}
//按指定位置查找元素
bool seekElem(DbLinkList*& L, int i, int& e)
{
DbLinkList* p;
int j = 1;
p = L->next;
if (!L || !L->next)
{
return false;
}
while (p && j < i)
{
p = p->next;
j++;
}
if (!p || j > i)
{
return false;
}
e = p->data;
return true;
}
bool DbLink_Delete(DbLinkList*& L, int i)
{
DbLinkNode* pos;
int j = 1;
pos = L->next;
if (!L || !L->next)
{
return false;
}
if (i < 1)
{
return false;
}
while (!pos ||j<i)
{
pos = pos->next;
j++;
}
if (!pos)
{
return false;
}
pos->prev->next = pos->next;
pos->next->prev = pos->prev;
delete pos;
return true;
}
//链表的销毁
void DestroyLink(DbLinkList* &L)
{
DbLinkNode* q = L;
if (!L)
{
cout << "链表为空" << endl;
}
while (q)
{
L = L->next;
delete q;
q = L;
}
cout << "链表销毁了" << endl;
}
void DbLink_Print(DbLinkList*& L)
{
DbLinkNode* s = NULL;
s = L;
if (!L)
{
cout << "链表为空." << endl;
return;
}
while (s->next)
{
s = s->next;
cout << s->data << "\t";
}
cout << endl;
while (s!=L)
{
cout << s->data << "\t";
s = s->prev;
}
cout << endl;
}
int main(void)
{
DbLinkList* L, * s, * a;
//双向链表初始化
if (DbLinkList_Init(L))
{
cout << "初始化循环链表成功" << endl;
}
else
{
cout << "初始化循环链表失败" << endl;
}
//前插
int j;
cout << "请输入你要插入的个数:";
cin >> j;
for (int i = 0; i < j; i++)
{
s = new DbLinkNode;
cin >> s->data;
InsertDbLink_front(L, s);
}
DbLink_Print(L);
//尾插
int z;
cout << "请输入你要插入的个数:";
cin >> z;
for (int i = 0; i < z; i++)
{
a = new DbLinkNode;
cin >> a->data;
InsertDbLink_front(L, a);
}
DbLink_Print(L);
//任意位置插入
int element, w;
cout << "请输入你要插入的数:";
cin >> w;
cout << "请输入你要插入的位置:";
cin >> element;
DbLink_Insert(L, element, w);
DbLink_Print(L);
//查找元素
int b;
cout << "请输入你要查找元素的位置:";
cin >> b;
seekElem(L, b, element);
cout << element << endl;
//删除指定位置的元素
DbLink_Delete(L, 3);
DbLink_Print(L);
//销毁链表
DestroyLink(L);
DbLink_Print(L);
system("pause");
return 0;
}