链表构成和实现
链表是由一群结点(node)所组成的链式结构
其中单链表的每一个节点可以顺次找到下一个节点 如图

其中节点是结构体,由两个部分组成,存数据的(数据域)和存指向下一个节点的地址的(指针域)
#include <iostream>
using namespace std;
struct Node
{
int data;
struct Node* next;
};
创建一个节点并打印其数据域试一试
int main()
{
struct Node node1 = { 10,NULL };
cout << node1.data;
return 0;
}
结果为10
现在我们按第一个图多创造几个节点并且连接起来,并测试连接性
int main()
{
struct Node node1 = { 10,NULL };
struct Node node2 = { 11,NULL };
struct Node node3 = { 12,NULL };
node1.next = &node2;
node2.next = &node3;
cout << node1.next << " " << node2.next;
return 0;
}
结果如图

链表的打印
现在我们试着打印整个链表的数据域
int main()
{
struct Node node1 = { 10,NULL };
struct Node node2 = { 11,NULL };
struct Node node3 = { 12,NULL };
node1.next = &node2;
node2.next = &node3;
struct Node* pMove = &node1;//创造一个可以移动的结构体指针pMove,并初始化使其指向node1(节点1)
while (pMove != NULL)//当pMove指向的节点的地址非空即节点存在时
{
cout << pMove->data<<" ";//当pMove本身是指针时可以用pMove->data表示pMove指向节点的数据域
pMove = pMove->next;//pMove->next是pMove对应的节点存储的指针域(下一个节点的地址)
}
return 0;
}
运行结果

现在我们试着实现一些插入的功能
首插法
首先我们先设计一个创建新节点的函数
struct Node* createNewNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));//sizeof是求Node结构体的大小,与结构体Node里的内容,类型多少有关,malloc()是动态内存分配函数,(struct Node*)再将返回值修改成结构体指针,newnode是一个创造出的结构体指针其对应一个创造出的结构体
newNode->data=data;
newNode->next = NULL;
return newNode;//返回newnode的地址即新创造的结构体的地址
}
然后我们开始进行链表的插入,首先试试往10 11 12前面插入7 8 9(首插法)
这个时候我们遇到了一个问题如果只插入9那么如下函数即可实现
void insertNodeByHead(struct Node* firstnode,int data)
{
struct Node* newNode = createNewNode(data);
newNode->next = firstnode;
}
但是这时我们不知道刚插入的9对应的节点名,无法表示首节点的地址和打印函数并且难以实现在9前面再插入8
所以我们在头结点前加入一个表头ListHead,那么首节点就一直是表头,这时问题即可解决
struct Node* listHeadNode = (struct Node*)malloc(sizeof(struct Node));//创建表头,malloc函数上面解释过
listHeadNode->next = &node1;//指针域指向node1
我们将首插法修改成
void insertNodeByHead(struct Node* ListHeadNode,int data)
{
struct Node* newNode = createNewNode(data);
newNode->next = ListHeadNode->next;//这时ListHeadNode->next代表的是node1;
ListHeadNode->next = newNode;//这个时候ListHeadNode->next代表的是newNode
}
将原有打印代码封装成函数
void printList(struct Node* listHeadNode)
{
struct Node* pMove = listHeadNode->next;
while (pMove != NULL)
{
cout << pMove->data << " ";
pMove = pMove->next;
}
}
至此我们可以实现可以将 7 8 9 插入到原有的10 11 12链表中,代码如下
#include <iostream>
using namespace std;
struct Node
{
int data;
struct Node* next;
};
struct Node* createNewNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
//首插法
void insertNodeByHead(struct Node* ListHeadNode,int data)
{
struct Node* newNode = createNewNode(data);
newNode->next = ListHeadNode->next;
ListHeadNode->next = newNode;
}
void printList(struct Node* listHeadNode)
{
struct Node* pMove = listHeadNode->next;
while (pMove != NULL)
{
cout << pMove->data << " ";
pMove = pMove->next;
}
}
int main()
{
struct Node node1 = { 10,NULL };
struct Node node2 = { 11,NULL };
struct Node node3 = { 12,NULL };
node1.next = &node2;
node2.next = &node3;
struct Node* listHeadNode = (struct Node*)malloc(sizeof(struct Node));
listHeadNode->next = &node1;
insertNodeByHead(listHeadNode, 9);
insertNodeByHead(listHeadNode, 8);
insertNodeByHead(listHeadNode, 7);
printList(listHeadNode);
return 0;
}
运行结果

尾插法
void insertNodeByTail(struct Node* ListHeadNode, int data)
{
struct Node* newNode = createNewNode(data);
struct Node* pMove =ListHeadNode ;
while (pMove->next)
{
pMove = pMove->next;
}
pMove->next = newNode;
newNode->next = NULL;
}
插入13 14 15
insertNodeByTail(listHeadNode, 13);
insertNodeByTail(listHeadNode, 14);
insertNodeByTail(listHeadNode, 15);
运行结果

指定插入法
将node3的值改成13便于理解
struct Node node3 = { 13,NULL };
此时为10 11 13
将12插在11 和13之间
void insertNodeByappointed(struct Node* listHeadNode, int data, int posData)
{
struct Node* posNodeFront = listHeadNode;//缩写成PF
struct Node* posNode = listHeadNode->next;//缩写成P
struct Node* newNode = createNewNode(data);//这时PF为表头,P为第一个节点,
if (posNode == NULL)
{
cout << "链表为空";
system("pause");
}//检查链表是否为空
else
{
while (posNode->data != posData)
{
posNodeFront = posNode;
posNode = posNode->next;
if(posNode==NULL)
{
cout << "未找到相关信息";
system("pause");
return ;//返回值不存在为空,仅表示退出程序
}//检查是否存在指定值
}
posNodeFront->next = newNode;
newNode->next = posNode;//将newNode插在PF和P之间
}
}
运行结果

首删法
void deleteNodeByHead(struct Node* listHeadNode)
{
struct Node* deleteNode = listHeadNode->next;
listHeadNode->next = deleteNode->next;
deleteNode = NULL;//置空,否则free函数可能会报错
free(deleteNode);
}

尾删法
void deleteNodeByTail(struct Node* listHeadNode) {
struct Node* pMove = listHeadNode;
struct Node* pMoveFront = NULL;
while (pMove->next)
{
pMoveFront = pMove;
pMove = pMove->next;
}
pMove = NULL;
free(pMove);
pMove = NULL;//置空,防止野指针
pMoveFront->next = NULL;
}

指定位置删除
void deleteNodeByAppointed(struct Node* listHeadNode,int posData)
{
struct Node* posNodeFront = listHeadNode;//缩写成PF
struct Node* posNode = listHeadNode->next;//缩写成P
if (posNode == NULL)
{
cout << "链表为空";
system("pause");
}//检查链表是否为空
else
{
while (posNode->data != posData)
{
posNodeFront = posNode;
posNode = posNode->next;
if (posNode == NULL)
{
cout << "未找到相关信息";
system("pause");
return;//返回值不存在为空,仅表示退出程序
}//检查是否存在指定值
}
posNodeFront->next = posNode->next;
posNode = NULL;
free(posNode);
posNode = NULL;
}
}
