// 殷人昆双向链表c第2版51页.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//2024-10-8---感受编程的技巧和乐趣
#include <iostream>
typedef int datatype;
using namespace std;
typedef struct node {
datatype data;
int freq;
struct node* rLink, * lLink;
}dblnode,*dblist;
void createR(dblist& first, datatype a[], int m)
{
first = (dblist)malloc(sizeof(dblnode));//create head 节点
first->lLink = first->rLink = first;//initalize
dblnode* s, * q, * rear = first;
for (int i = 0; i < m; i++)
{
s = (dblist)malloc(sizeof(dblnode));
s->data = a[i];
//相当于双向循环链表的插入
q = rear->rLink; s->lLink = rear; q->lLink = s;//前驱方向链接
s->rLink = q; rear->rLink = s; rear = s;//后继方向链接
//借助指针q记录rear的后继地址,避免断链
}
}
void printlist(dblist first)
{
dblist p;
p = first->rLink;
while (p != first)
{
cout << p->data << " ";
p = p->rLink;
}
cout << endl;
}
dblist search(dblist first,datatype x)
{
dblist p = first->rLink;
while (p != first && p->data != x)//动动脑子,再写
{
p = p->rLink;
}
return (p != first) ? p : NULL;//NULL是p==first的情况没有找到
}
dblist locate(dblist first, int i)
{
if (i < 0)return NULL;//i=0是头节点,i<0插入位置不合理
if (i == 0)return first;
dblist p = first->rLink;
for (int j = 1; j < i; j++)
{
if (p == first)
{
break;//i太大,链太短
}else {
p = p->rLink;
}
}
return (p != first) ? p : NULL;//NULL是first==p位置小于0,或i>链表长度
}
int insert(dblist& first, int i, datatype x, int d)
{
dblist p = locate(first,i-1);
if (p == NULL)return 0;//i-1<0或i-1>长度,插入位置不合理
dblist s = new dblnode;
s->data = x;
if (d == 0)//前驱方向加入
{
s->rLink = p; s->lLink = p->lLink;//我采用的是保险的做法,先解决插入节点,这样不会断链
p->lLink->rLink = s; p->lLink = s;//为了不断链,最后修改p->lLink
}
else//后继
{
s->rLink = p->rLink; s->lLink = p;
p->rLink->lLink = s; p->rLink = s;//为了不断链,最后修改p->rLink
}
return 1;
}
int insert_yinrenkun(dblist& first, int i, datatype x, int d)
{
dblist p = locate(first, i - 1);
if (p == NULL)return 0;//i-1<0或i-1>长度,插入位置不合理
dblist s = new dblnode;
s->data = x;
if (d == 0)//前驱方向加入
{
s->lLink = p->lLink; p->lLink = s;//前驱链
s->lLink->rLink = s; s->rLink = p;//后继链
}
else//后继
{
s->rLink = p->rLink; p->rLink = s;//后继链
s->rLink->lLink = s; s->lLink = p;//前驱链
}
return 1;
}
int remove_wanghongmei(dblist& first, int i, datatype& x)
{
dblist p = locate(first,i);
if (p == NULL)return 0;//空表或位置不对,删除位置1<=i=<长度
p->lLink->rLink = p->rLink;
p->rLink->lLink = p->lLink;
x = p->data;
free(p);
p = NULL;
return 1;
}
int remove(dblist& first, int i, datatype& x)
{
dblist p = locate(first,i);
if (p == NULL)return 0;
p->rLink->lLink = p->lLink;
p->lLink->rLink = p->rLink;
free(p);
return 1;
}
int main()
{
int a[6] = {2,3,5,7,9,1};
dblist first;
createR(first, a, 6);
printlist(first);
dblist p = search(first, 9);
cout << p->data<<endl;
p = locate(first,3);
cout << p->data << endl;
p = locate(first, 7);
if (p == NULL) {
cout << "p==null" << endl;
}
insert_yinrenkun(first, 4, 6, 1);
printlist(first);
datatype x;
remove_wanghongmei(first, 4, x);
printlist(first);
std::cout << "Hello World!\n";
}
解决问题:王红梅老师的删除节点----修改指针两条语句可以颠倒吗?可以,殷人昆就是这样做的
另外解决问题之前,自己先想想!!!!
仔细体会殷人昆老师的代码和习题,里面有很多编程的小技巧!!!
关于插入操作-----上面的代码不是唯一的,但也不可以任意排序 思考:第一步和第二步是不是必须在第四步最后??上面的代码不是唯一的,但也不可以任意排序 ;;;否则*p的后继节点的指针就会丢掉,插入失败。
建议做题时画图 切不可死记
例如:尾插法---我根据循环链表进行了修改
void createRear(dblist& first, datatype a[], int m)//我自己写的---根据单链表的尾插法
{
first = new dblnode;
first->lLink = first->rLink=first;
dblist s, rear = first;
for (int i = 0; i < m; i++)
{
s = new dblnode;
s->data = a[i];
s->lLink = rear;
s->rLink = rear->rLink;
rear->rLink = s;//上面两句和这一句修改指针将s节点插入到链表尾部
rear = s;//rear后移,指向目前最后一个节点
}
}