数据结构主要研究数据的组织方式以及相应的操作方法。它除了描述数据本身之外, 还描述数据之间的相互关系。它不仅是一般程序设计的基础,而且是设计编译程序、操作 系统、数据库、人工智能及其他大型应用程序的基础。如今,数据结构在计算机科学中占 有重要的地位。对于相当多的程序设计来说,认清数据的内在关系,可获得对问题的正确 认识,看清问题的结构甚至解法。在一定意义上,程序所描述的就是在数据结构上实现的 算法。算法的设计依赖于数据的逻辑结构,算法的实现依赖于数据的存储结构,所以数据 结构选择得好坏,对程序质量的影响甚大。掌握基本的数据结构知识,是提高程序设计水 平的必要条件。
面试题13 编程实现一个双向链表的建立
考点:双向链表的操作
出现频率:★★★★
【解析】
双向链表的定义如下。
typedef struct DbNode
{
int data; //节点数据
DbNode* left; //前驱节点指针
DbNode* right; //后继节点指针
}DbNode;
(1)建立双向链表:为方便,这里定义了3个函数。
CreateNode()根据数据来创建一个节点,返回新创建的节点。
CreateList()函数根据一个节点数据创建链表的表头,返回表头节点。
AppendNode ()函数总在表尾插入新节点(其内部调用CreateNode()生成节点),返回表 头节点。
//根据数据创建创建节点
DbNode* CreateNode(int data)
{
DbNode* pnode = (DbNode*)malloc(sizeof(DbNode));
pnode->data = data;
pnode->left = pnode->right = pnode; //创建新节点时
//让其前驱和后继指针都指向自身
return pnode;
}
//创建链表
DbNode* CreateList(int head) //参数给出表头节点数据
{ //表头节点不作为存放有意义数据的节点
DbNode* pnode = (DbNode*)malloc(sizeof(DbNode));
pnode->data = head;
pnode->left = pnode->right = pnode;
return pnode;
}
//插入新节点,总是在表尾插入;返回表头节点
DbNode* AppendNode(DbNode* head, int data) //参数1是链表的表头节点
{ //参数2是要插入的节点,其数据为data
DbNode* node = CreateNode(data); //创建数据为data的新节点
DbNode* p = head, * q{ nullptr };
while (p != nullptr)
{
q = p;
p = p->right;
}
q->right = node;
node->left = q;
return head;
}
我们可以使用其中的CreateList()和AppendNode()来生成一个链表。下面是一个数据生 成从0到9含有10个节点的循环链表。
DbNode* head = CreateList(0); //生成表头,表头数据为0
for (int i = 1; i < 10; i++)
{
head = AppendNode(head, i); //添加9个节点,数据为从1到9
}
面试题14 编程实现一个双向链表的测长
考点:双向链表的操作
出现频率:★★★★
【解析】
为了得到双向链表的长度,需要使用right指针进行遍历,直到得到NULL为止。
//获取链表的长度
int GetLength(DbNode* head) //参数为链表的表头节点
{
int count = 1;
DbNode* pnode = nullptr;
if (head == nullptr) //head为nullptr表示链表空
{
return 0;
}
pnode = head->right;
while (pnode != nullptr)
{
pnode = pnode->right; //使用right指针遍历
count++;
}
return count;
}
面试题15 编程实现一个双向链表的打印
考点:双向链表的操作
出现频率:★★★★
【解析】
与测长的方法一样,使用right指针进行遍历。
//打印整个链表
void PrintList(DbNode* head) //参数为链表的表头节点
{
DbNode* pnode = nullptr;
if (head == nullptr) //head为nullptr表示链表空
{
return;
}
pnode = head;
while (pnode != nullptr) //使用right指针遍历
{
printf("%d ", pnode->data);
pnode = pnode->right;
}
printf("\n");
}
面试题16 编程实现一个双向链表节点的查找
考点:双向链表的操作
出现频率:★★★★
【解析】
使用right指针遍历,直至找到数据为data的节点。如果找到节点,返回节点,否则返 回NULL。
//查找节点,成功则返回满足条件的节点指针,否则返回NULL
DbNode* FindNode(DbNode* head, int data) //参数1是链表的表头节点
{ //参数2是要查找的节点,其数据为data
DbNode* pnode = head;
if (head == nullptr) //链表为空时返回nullptr
{
return nullptr;
}
//找到数据或者到达链表末尾,退出while循环
while (pnode->right != nullptr && pnode->data != data)
{
pnode = pnode->right; //使用right指针遍历
}
//没有找到数据为data的节点,返回nullptr
if (pnode->right == nullptr)
{
return nullptr;
}
return pnode;
}
面试题17 编程实现一个双向链表节点的插入
考点:双向链表的操作
出现频率:★★★★
【解析】
节点p后插入一个节点。
这里分为两种插入情况:一种是插入位置在中间,另一种是插入位置在末尾。两种情
况有一点不同:插入位置在中间时需要把p的原后继节点的前驱指针指向新插入的节点。
//在node节点之后插入新节点
void InsertNode(DbNode* node, int data)
{
DbNode* newnode = CreateNode(data);
DbNode* p = nullptr;
if (node == nullptr) //node为nullptr时返回
{
return;
}
if (node->right == nullptr) //node为最后一个节点
{
node->right = newnode;
newnode->left = node;
}
else
{ //node为中间节点
newnode->right = node->right; //newnode向右连接
node->right->left = newnode;
node->right = newnode; //newnode向左连接
newnode->left = node;
}
}
面试题18 编程实现一个双向链表节点的删除
考点:双向链表的操作
DbNode* DeleteNode(DbNode* head, int data) //参数1是链表的表头节点
{ //参数2是要插入的节点,其数据为data
DbNode* ptmp = nullptr;
DbNode* pnode = FindNode(head, data); //查找节点
if (nullptr == pnode) //节点不存在,返回nullptr
{
return nullptr;
}
else if (pnode->left == nullptr) //node为第一个节点
{
head = pnode->right;
if (head != nullptr) //链表不为空
{
head->left = nullptr;
}
}
else if (pnode->right == nullptr) //node为最后一个节点
{
pnode->left->right = nullptr;
}
else //node为中间的节点
{
pnode->left->right = pnode->right;
pnode->right->left = pnode->left;
}
free(pnode); //释放已被删除的节点空间
return head;
}
面试题19 实现有序双向循环链表的插入操作
考点:双向循环链表的操作
出现频率:★★★
【解析】
源代码如下。
#include <iostream>
using namespace std;
typedef struct DbNode
{
int data; //节点数据
DbNode* left{nullptr}; //前驱节点指针
DbNode* right{ nullptr }; //后继节点指针
}DbNode;
//根据数据创建创建节点
DbNode* CreateNode(int data)
{
DbNode* pnode = (DbNode*)malloc(sizeof(DbNode));
pnode->data = data;
pnode->left = pnode; //创建新节点时
pnode->right = pnode;
//让其前驱和后继指针都指向自身
return pnode;
}
//创建链表
DbNode* CreateList(int head) //参数给出表头节点数据
{ //表头节点不作为存放有意义数据的节点
DbNode* pnode = (DbNode*)malloc(sizeof(DbNode));
pnode->data = head;
pnode->left = pnode;
pnode->right = pnode;
return pnode;
}
//插入新节点,总是在表尾插入;返回表头节点
DbNode* AppendNode(DbNode* head, int data) //参数1是链表的表头节点
{ //参数2是要插入的节点,其数据为data
DbNode* node = CreateNode(data); //创建数据为data的新节点
DbNode* p{nullptr}, * q{nullptr};
if (head == nullptr)
{
return nullptr;
}
q = head->right;
p = head->right;
while (p != head)
{
q = p;
p = p->right;
}
q->right = node;
node->left = q;
node->right = head;
head->left = node;
return head;
}
//获取链表的长度
int GetLength(DbNode* head) //参数为链表的表头节点
{
int count = 1;
DbNode* pnode = nullptr;
if (head == nullptr) //head为nullptr表示链表空
{
return 0;
}
pnode = head->right;
while (pnode != nullptr)
{
pnode = pnode->right; //使用right指针遍历
count++;
}
return count;
}
//15
//打印整个链表
void PrintList(DbNode* head) //参数为链表的表头节点
{
DbNode* pnode = nullptr;
if (head == nullptr) //head为nullptr表示链表空
{
return;
}
printf("%d ", head->data);
pnode = head;
while (pnode != head) //使用right指针遍历
{
printf("%d ", pnode->data);
pnode = pnode->right;
}
printf("\n");
}
//16
//查找节点,成功则返回满足条件的节点指针,否则返回NULL
DbNode* FindNode(DbNode* head, int data) //参数1是链表的表头节点
{ //参数2是要查找的节点,其数据为data
DbNode* pnode = head;
if (head == nullptr) //链表为空时返回nullptr
{
return nullptr;
}
//找到数据或者到达链表末尾,退出while循环
while (pnode->right != nullptr && pnode->data != data)
{
pnode = pnode->right; //使用right指针遍历
}
//没有找到数据为data的节点,返回nullptr
if (pnode->right == nullptr)
{
return nullptr;
}
return pnode;
}
//17
插入一个有序链表(从小到大排列),返回表头
DbNode* InsertNode(DbNode* head, int data)
{
DbNode* p{nullptr};
DbNode* q{ nullptr };
DbNode* node{ nullptr };
node = CreateNode(data); //新建数据节点
if (head == nullptr) //空链表,返回新建节点
{
head = node;
return node;
}
if (head->data > data) //data小于表头数据,插入到表头之前
{ //把新建节点作为表头
head->left->right = node; //末节点后继指针指向node
node->left = head->left; //node的前驱指针指向末节点
node->right = head; //node的后继指针指向head
head->left = node; //head的前驱指针指向node
return node;
}
p = head->right;
while (p->data <= data && p != head)
{
p = p->right;
}
p = p->left;
q = p->right;
//把node插入p和q之间
p->right = node;
node->left = p;
node->right = q;
q->left = node;
return head;
}
//18
//删除满足指定条件的节点,返回表头节点,删除失败,返回NULL(失败的原因是不存在该节点)
DbNode* DeleteNode(DbNode* head, int data) //参数1是链表的表头节点
{ //参数2是要插入的节点,其数据为data
DbNode* ptmp = nullptr;
DbNode* pnode = FindNode(head, data); //查找节点
if (nullptr == pnode) //节点不存在,返回nullptr
{
return nullptr;
}
else if (pnode->left == nullptr) //node为第一个节点
{
head = pnode->right;
if (head != nullptr) //链表不为空
{
head->left = nullptr;
}
}
else if (pnode->right == nullptr) //node为最后一个节点
{
pnode->left->right = nullptr;
}
else //node为中间的节点
{
pnode->left->right = pnode->right;
pnode->right->left = pnode->left;
}
free(pnode); //释放已被删除的节点空间
return head;
}
int main()
{
DbNode* head = CreateList(1); //生成表头,表头数据为1
AppendNode(head, 3);
AppendNode(head, 6);
AppendNode(head, 8);
PrintList(head);
head = InsertNode(head, 0);
PrintList(head);
head = InsertNode(head, 4);
PrintList(head);
head = InsertNode(head, 10);
PrintList(head);
cout << "hello world" << endl;
return 0;
}
下面是各个函数的简单说明。
CreateNode()根据数据创建节点,包括头节点和一般节点。创建头节点时,left和right 指针都指向本身来形成环状。
AppendNode()插入新节点,总是在末尾插入。返回表头节点。 PrintList()打印整个链表,由于属于循环链表,因此遍历回到head节点时结束打印。
InsertNode()数据插入一个升序的链表,返回表头节点。这里插入位置分为表头和非表 头两种情况。如果是表头,返回的指针是新的节点,否则返回的是原来的表头节点。
main()函数建立了一个升序链表,并对它的不同位置进行了插入操作。 执行结果如下。
面试题20 删除两个双向循环链表的相同结点
考点:双向循环链表的操作
出现频率:★★★
有两个双向循环链表A,B,知道其头指针分别为pHeadA,pHeadB。请写一个函数, 将两链表中data值相同的节点删除。
【解析】
可以这样来处理:
(1)把A中含有的与B中相同的数据节点抽出来,组成一个新的链表,例如
链表A: 1 2 3 4 2 6 4
链表B: 10 20 3 4 2 10
新建链表C: 2 3 4
(2)遍历链表C,删除A和B的所有节点。如果A含有数据相等的节点(A有两个4), 且B也含有此数据节点(B也有4),则A中数据相等的节点全部被删除。
根据以上分析,我们实现了以下函数。
(1)GetLink()函数,其源代码如下。
//GetLink()通过headA值表和headB链表中相同的数据节点,得到一个新的链表
DbNode* GetLink(DbNode* headA, DbNode* headB)
{
int i = 0;
DbNode* newHead{ nullptr }; //返回新的链表
DbNode* pnodeA = headA; //遍历headA
DbNode* pnodeB = headB; //遍历headB
DbNode* pnode = nullptr; //遍历newhead
do
{
DbNode* node = nullptr; //用于查看新的链表中是否已经存在节点数据
pnodeB = headB;
if ((node = FindNode(newHead, pnodeA->data)) != nullptr)
{
//若newHead中已含有此节点数据,则不考虑此节点的比较,进行下一次遍历
pnodeA = pnodeA->right;
continue;
}
do
{
if (pnodeA->data == pnodeB->data) //找到A与B中相同的数据节点
{
i++;
if (i == 1) //第一次生成头节点
{
newHead = CreateNode(pnodeA->data);
}
else //不是第一次,添加节点
{
AppendNode(newHead, pnodeA->data);
}
break;
}
pnodeB = pnodeB->right; //对链表B进行遍历
} while (pnodeB != headB);
pnodeA = pnodeA->right; //对链表A进行遍历
} while (pnodeA != headA);
return newHead;
}
GetLink()把A和B的两个链表头节点指针传入,返回一个链表头节点指针。这里有下 面几点需要说明。
由于要遍历A和B,因此需要使用了嵌套的循环。外层是对链表A进行遍历的,内层 是对链表B进行遍历的。
当找到A、B的相同数据后,由于新建表头节点情况(使用CreateNode函数)与插入 节点情况(AppendNode函数)不同,因此代码第25~33行进行了区别对待。
出于效率的考虑,代码第15~20行首先判断A当前节点的数据是否已经在新建的链表 中,如果已经存在,则不进行B的遍历,继续进行A的下一个节点的判断。
(2)DeleteNode函数,其源代码如下。
//酬除链表中所有数据等于Value的节点
DbNode* DeleteNode(DbNode* pHeader, int Value)
{
DbNode* pNode = nullptr;
DbNode* pNodeRight = nullptr;
int bRet = 0;
if (pHeader == nullptr)
return nullptr;
while(pHeader->data == Value) //头节点的数据为Value,删除
{
pNode = pHeader->right;
if (pHeader == pHeader->right) //链表只剩下一个元素
{
free(pHeader); //除节点,此时链表为空,返回nullptr
return nullptr;
}
//链表还有其他节点,把原来头节点的左、右两个节点相连
pHeader->left->right = pHeader->right;
pHeader->right->left = pHeader->left;
free(pHeader); //释放头节点内存
pHeader = pNode; //把原来头节点的下一个节点作为新的头节点
}
pNode = pHeader->right; //要删除的不是头节点
while (pNode != pHeader) //遍历链表,直到回到头节点
{
pNodeRight = pNode->right; //保存下一个节点
if (pNode->data == Value) //如果搜索到Value,删除此节点
{
pNode->left->right = pNodeRight;
pNodeRight->left = pNode->left;
free(pNode);
}
pNode = pNodeRight; //指向下一个节点
}
return pHeader;
}
DeleteNode()传入的参数为链表头节点的指针以及需要删除的数据值,返回删除后的头 节点指针。有下面几点需要说明。
口 当删除的节点为头节点时,此时需要考虑两种情况,即链表中只有一个头节点, 以及删除后的头节点数据也等于Value值。代码第13~17行对第一种情况进行了
判断,代码第10行的while循环是出于第二种情况的考虑。另外,头节点为下一 个节点(pHeader发生了变化)。
□当删除的节点不是头节点时,简单地进行循环,搜索数据为Value的节点并删除之, 直到当前节点回到头节点结束。
(3)DeleteEqual ()函数,其源代码如下。
//DeleteEqual删除ppHeadA与ppHeadB两个链表所有含相同数据的节点
//参数ppHeadA和ppHeadB分别为链表A和链表B头节点指针的地址
void DeleteEqual(DbNode** ppHeadA, DbNode** ppHeadB)
{
DbNode* pHeadA = *ppHeadA, * pHeadB = *ppHeadB;
DbNode* head = nullptr;
if (ppHeadA == nullptr || ppHeadB == nullptr) //ppHeadA或ppHeadB不合法
{
return;
}
if (pHeadA == nullptr || pHeadB == nullptr) //链表A或B有一个为空
{
return;
}
head = GetLink(pHeadA, pHeadB); //获得A和B的相同数据节点所构成的链表
while (head != nullptr)
{
pHeadA = DeleteNode(pHeadA, head->data); //删除A中所有head的数据节点
pHeadB = DeleteNode(pHeadB, head->data); //删除A中所有head的数据节点
head = DeleteNode(head, head->data); //删除head当前节点
}
*ppHeadA = pHeadA; //返回ppheadA
*ppHeadB = pHeadB; //返回ppHeadB
}
DeleteEqualO是最终的调用函数,它首先判断传入参数的有效性,然后调用前面的 GetLinkO)得到链表A和链表B的相同数据所构成的新链表(代码第17行),最后调用前面 的DeleteNode()循环删除各个链表中的节点(代码第18~23行)。
注意:由于DeleteEqual()函数有可能删除链表A和B的头节点,为了保存函数返回后 A和B的头节点,参数必须使用指针的地址或者指针的引用(C++中可行)。这里使用的是 指针的地址,所以在最后(代码第25、26行)保存链表头节点指针。
#include <iostream>
using namespace std;
typedef struct DbNode
{
int data; //节点数据
DbNode* left{nullptr}; //前驱节点指针
DbNode* right{ nullptr }; //后继节点指针
}DbNode;
//根据数据创建创建节点
DbNode* CreateNode(int data)
{
DbNode* pnode = (DbNode*)malloc(sizeof(DbNode));
pnode->data = data;
//pnode->left = pnode; //创建新节点时
//pnode->right = pnode;
//让其前驱和后继指针都指向自身
return pnode;
}
//创建链表
DbNode* CreateList(int head) //参数给出表头节点数据
{ //表头节点不作为存放有意义数据的节点
DbNode* pnode = (DbNode*)malloc(sizeof(DbNode));
pnode->data = head;
pnode->left = nullptr;
pnode->right = nullptr;
return pnode;
}
//插入新节点,总是在表尾插入;返回表头节点
DbNode* AppendNode(DbNode* head, int data) //参数1是链表的表头节点
{ //参数2是要插入的节点,其数据为data
DbNode* node = CreateNode(data); //创建数据为data的新节点
DbNode* p{nullptr}, * q{nullptr};
if (head == nullptr)
{
return nullptr;
}
q = head->right;
p = head->right;
while (p != head)
{
q = p;
p = p->right;
}
q->right = node;
node->left = q;
node->right = head;
head->left = node;
return head;
}
//尾插
void LTPushBack(DbNode* phead, int x)
{
if (phead == nullptr)
return;
DbNode* newnode = CreateNode(x);
DbNode* p{nullptr};
DbNode* q{ nullptr };
if (phead->right == nullptr) //如果头结点指向的数据为空,直接加到头结点后面。
{
phead->right = newnode;
newnode->left = phead;
newnode->right = nullptr;
}
else
{
p = phead->right; //已存在数据链表,让p指向最后一个结点。
while (p->right != nullptr)
{
p = p->right; //使用right指针遍历
}
p->right = newnode;
newnode->left = p;
newnode->right = nullptr;
}
}
//获取链表的长度
int GetLength(DbNode* head) //参数为链表的表头节点
{
int count = 1;
DbNode* pnode = nullptr;
if (head == nullptr) //head为nullptr表示链表空
{
return 0;
}
pnode = head->right;
while (pnode != nullptr)
{
pnode = pnode->right; //使用right指针遍历
count++;
}
return count;
}
//15
//打印整个链表
void PrintList(DbNode* head) //参数为链表的表头节点
{
DbNode* pnode = nullptr;
if (head == nullptr) //head为nullptr表示链表空
{
return;
}
printf("%d ", head->data);
pnode = head->right;
while (pnode != nullptr) //使用right指针遍历
{
printf("%d ", pnode->data);
pnode = pnode->right;
}
printf("\n");
}
//16
//查找节点,成功则返回满足条件的节点指针,否则返回NULL
DbNode* FindNode(DbNode* head, int data) //参数1是链表的表头节点
{ //参数2是要查找的节点,其数据为data
DbNode* pnode = head;
if (head == nullptr) //链表为空时返回nullptr
{
return nullptr;
}
//找到数据或者到达链表末尾,退出while循环
while (pnode->right != nullptr && pnode->data != data)
{
pnode = pnode->right; //使用right指针遍历
}
//没有找到数据为data的节点,返回nullptr
if (pnode->right == nullptr)
{
return nullptr;
}
return pnode;
}
//17
DbNode* InsertNode(DbNode* node, int data)
{
DbNode* p{ nullptr };
DbNode* newnode = CreateNode(data); //新建数据节点
if (node == nullptr) //空链表,返回新建节点
{
return nullptr;
}
if (node->right == nullptr)
{
node->right = newnode;
newnode->left = node;
}
else
{
newnode->right = node->right;
node->right->left = newnode;
node->right = newnode;
newnode->left = node;
}
return node;
}
//插入一个有序链表(从小到大排列),返回表头
DbNode* InsertNode1(DbNode* head, int data)
{
DbNode* p{nullptr};
DbNode* q{ nullptr };
DbNode* node{ nullptr };
node = CreateNode(data); //新建数据节点
if (head == nullptr) //空链表,返回新建节点
{
head = node;
return node;
}
if (head->data > data) //data小于表头数据,插入到表头之前
{ //把新建节点作为表头
node->left = head->left; //node的前驱指针指向末节点
node->right = head; //node的后继指针指向head
head->left = node; //head的前驱指针指向node
return node;
}
p = head->right;
while (p->data <= data && p != head && p->right != nullptr)
{
p = p->right;
}
if (p->right == nullptr && p->data <= data) //说明已到达最后一个元素,这时直接把它加入到最后即可
{
p->right = node;
node->left = p;
node->right = nullptr;
}
else
{
p = p->left;
q = p->right;
//把node插入p和q之间
p->right = node;
node->left = p;
node->right = q;
q->left = node;
}
return head;
}
//18
//删除满足指定条件的节点,返回表头节点,删除失败,返回NULL(失败的原因是不存在该节点)
//DbNode* DeleteNode(DbNode* head, int data) //参数1是链表的表头节点
//{ //参数2是要插入的节点,其数据为data
// DbNode* ptmp = nullptr;
//
// DbNode* pnode = FindNode(head, data); //查找节点
// if (nullptr == pnode) //节点不存在,返回nullptr
// {
// return nullptr;
// }
// else if (pnode->left == nullptr) //node为第一个节点
// {
// head = pnode->right;
// if (head != nullptr) //链表不为空
// {
// head->left = nullptr;
// }
// }
// else if (pnode->right == nullptr) //node为最后一个节点
// {
// pnode->left->right = nullptr;
// }
// else //node为中间的节点
// {
// pnode->left->right = pnode->right;
// pnode->right->left = pnode->left;
// }
//
// free(pnode); //释放已被删除的节点空间
// return head;
//}
//20
//GetLink()通过headA值表和headB链表中相同的数据节点,得到一个新的链表
DbNode* GetLink(DbNode* headA, DbNode* headB)
{
int i = 0;
DbNode* newHead{ nullptr }; //返回新的链表
DbNode* pnodeA = headA; //遍历headA
DbNode* pnodeB = headB; //遍历headB
DbNode* pnode = nullptr; //遍历newhead
do
{
DbNode* node = nullptr; //用于查看新的链表中是否已经存在节点数据
pnodeB = headB;
if ((node = FindNode(newHead, pnodeA->data)) != nullptr)
{
//若newHead中已含有此节点数据,则不考虑此节点的比较,进行下一次遍历
pnodeA = pnodeA->right;
continue;
}
do
{
if (pnodeA->data == pnodeB->data) //找到A与B中相同的数据节点
{
i++;
if (i == 1) //第一次生成头节点
{
newHead = CreateNode(pnodeA->data);
}
else //不是第一次,添加节点
{
AppendNode(newHead, pnodeA->data);
}
break;
}
pnodeB = pnodeB->right; //对链表B进行遍历
} while (pnodeB != headB);
pnodeA = pnodeA->right; //对链表A进行遍历
} while (pnodeA != headA);
return newHead;
}
//酬除链表中所有数据等于Value的节点
DbNode* DeleteNode(DbNode* pHeader, int Value)
{
DbNode* pNode = nullptr;
DbNode* pNodeRight = nullptr;
int bRet = 0;
if (pHeader == nullptr)
return nullptr;
while(pHeader->data == Value) //头节点的数据为Value,删除
{
pNode = pHeader->right;
if (pHeader == pHeader->right) //链表只剩下一个元素
{
free(pHeader); //除节点,此时链表为空,返回nullptr
return nullptr;
}
//链表还有其他节点,把原来头节点的左、右两个节点相连
pHeader->left->right = pHeader->right;
pHeader->right->left = pHeader->left;
free(pHeader); //释放头节点内存
pHeader = pNode; //把原来头节点的下一个节点作为新的头节点
}
pNode = pHeader->right; //要删除的不是头节点
while (pNode != pHeader) //遍历链表,直到回到头节点
{
pNodeRight = pNode->right; //保存下一个节点
if (pNode->data == Value) //如果搜索到Value,删除此节点
{
pNode->left->right = pNodeRight;
pNodeRight->left = pNode->left;
free(pNode);
}
pNode = pNodeRight; //指向下一个节点
}
return pHeader;
}
//DeleteEqual删除ppHeadA与ppHeadB两个链表所有含相同数据的节点
//参数ppHeadA和ppHeadB分别为链表A和链表B头节点指针的地址
void DeleteEqual(DbNode** ppHeadA, DbNode** ppHeadB)
{
DbNode* pHeadA = *ppHeadA, * pHeadB = *ppHeadB;
DbNode* head = nullptr;
if (ppHeadA == nullptr || ppHeadB == nullptr) //ppHeadA或ppHeadB不合法
{
return;
}
if (pHeadA == nullptr || pHeadB == nullptr) //链表A或B有一个为空
{
return;
}
head = GetLink(pHeadA, pHeadB); //获得A和B的相同数据节点所构成的链表
while (head != nullptr)
{
pHeadA = DeleteNode(pHeadA, head->data); //删除A中所有head的数据节点
pHeadB = DeleteNode(pHeadB, head->data); //删除A中所有head的数据节点
head = DeleteNode(head, head->data); //删除head当前节点
}
*ppHeadA = pHeadA; //返回ppheadA
*ppHeadB = pHeadB; //返回ppHeadB
}
int main()
{
DbNode* head = CreateList(1); //生成表头,表头数据为1
//AppendNode(head, 3);
//AppendNode(head, 6);
//AppendNode(head, 8);
LTPushBack(head, 3);
LTPushBack(head, 6);
LTPushBack(head, 8);
printf("len = %d\n", GetLength(head));
PrintList(head);//1 3 6 8
head = InsertNode1(head, 0);
PrintList(head);
head = InsertNode1(head, 10);
PrintList(head);
head = InsertNode1(head, 2);
PrintList(head);
head = InsertNode1(head, 9);
PrintList(head);
cout << "hello world" << endl;
return 0;
}
运行结果: