1. 链表的基本概念
数组修改起来不方便,需要进行大量移动,但是数组有下标,查找第几号数据比较方便,链表对于数组操作比较快,但是不能按下标进行快速查找。
拿到链表的第一个节点,就相当于拿到整个链表。
如果链表没有头部,在插入节点时,要判断插入的位置是不是第一个位置。
如果链表有头部节点,在第一个位置插入新节点,也就是在头部节点的下一个位置插入,头节点的next永远是第一个元素。
2. 静态链表
#include<iostream>
using namespace std;
// 静态链表
struct LinkNode
{
int data;
struct LinkNode* next;
};
// 创建链表
void test()
{
// 拿到node1就相当于拿到整个链表
struct LinkNode node1 = { 10,NULL };
struct LinkNode node2 = { 20,NULL };
struct LinkNode node3 = { 30,NULL };
struct LinkNode node4 = { 40,NULL };
struct LinkNode node5 = { 50,NULL };
struct LinkNode node6 = { 60,NULL };
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
node4.next = &node5;
// 如何遍历链表?--判断指针域指向的是否为空
// 先定义一个辅助指针变量
struct LinkNode* pCurrent = &node1;
while (pCurrent != NULL)
{
printf("%d ", pCurrent->data);
// 指针移动到下一个元素的首地址
pCurrent = pCurrent->next;
}
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
输出:
3. 动态链表
头文件LinkList.h
#pragma once // 防止头文件重复包含
#include<iostream>
using namespace std;
// 定义节点数据类型
struct MyLinkNode
{
int data;
struct MyLinkNode* next;
};
// 初始化链表
struct MyLinkNode* MyInit_LinkList();
//在值为oldval的位置插入一个新的数据newval,此时需要设置三个节点
void InsertByValue_LinkList(struct MyLinkNode* header, int oldval, int newval);
//删除值为val的节点
void RemoveByValue_LinkList(struct MyLinkNode* header, int deValue);
//遍历
void MyForeach_LinkList(struct MyLinkNode* header);
//销毁
void Destroy_LinkList(struct MyLinkNode* header);
//清空
void Clear_LinkList(struct MyLinkNode* header);
函数编写文件LinkList.cpp
#include "LinkList.h"
#include<iostream>
using namespace std;
// 初始化链表
struct MyLinkNode* MyInit_LinkList()
{
//创建头节点
struct MyLinkNode* header = (struct MyLinkNode*)malloc(sizeof(struct MyLinkNode));
header->data = -1;
header->next = NULL;
// 初始化尾部指针为头部指针
struct MyLinkNode* pRear = header;
int val = -1;
while (true)
{
cout << "输入插入的数据:" << endl;
cin >> val;
if (val == -1)
{
break;
}
// 先创建新节点
struct MyLinkNode* newNode = (struct MyLinkNode*)malloc(sizeof(struct MyLinkNode));
newNode->data = val;
newNode->next = NULL;
//LinkNode
pRear->next = newNode;
//更新尾部指针指向
pRear = newNode;
}
return header; //返回头部链表
}
//在值为oldval的位置插入一个新的数据newval
void InsertByValue_LinkList(struct MyLinkNode* header, int oldval, int newval)
{
if (NULL == header)
{
return;
}
// 两个辅助指针变量
struct MyLinkNode* pPrev = header;
struct MyLinkNode* pCurrent = pPrev->next;
while (pCurrent != NULL)
{
if (pCurrent->data == oldval)
{
break;
}
pPrev = pCurrent;
pCurrent = pCurrent->next;
}
#if 0 //注释掉此段,可以实现:如果没有oldval,直接将其插入尾部
// 如果pCurrent为空,说明链表中不存在值为oldval的节点
if (pCurrent == NULL)
{
return;
}
#endif
// 先创建新节点
struct MyLinkNode* newnode = (struct MyLinkNode*)malloc(sizeof(struct MyLinkNode));
newnode->data = newval;
newnode->next = NULL;
//新节点插入到链表中
//pPrev地址域放newnode地址,newnode地址域放pCurrent地址,也就是当前oldval地址
newnode->next = pCurrent;
pPrev->next = newnode;
}
//删除值为val的节点
void RemoveByValue_LinkList(struct MyLinkNode* header, int deValue)
{
if (NULL == header)
{
return;
}
struct MyLinkNode* pPrev = header;
struct MyLinkNode* pCurrent = pPrev->next;
while (pCurrent != NULL)
{
if (pCurrent->data == deValue)
{
break;
}
//移动两个指针
pPrev = pCurrent;
pCurrent = pCurrent->next;
}
if (pCurrent == NULL)
{
return;
}
//重新建立待删除节点的前驱和后继节点关系
pPrev->next = pCurrent->next;
//释放删除的节点内存
free(pCurrent);
pCurrent = NULL;
}
//遍历
void MyForeach_LinkList(struct MyLinkNode* header)
{
if (NULL == header)
{
return;
}
//辅助指针变量
struct MyLinkNode* pCurrent = header->next;//还是header->next?
while (pCurrent != NULL)
{
cout << pCurrent->data << endl;
pCurrent = pCurrent->next;
}
}
//销毁--需要设置两个移动节点
void Destroy_LinkList(struct MyLinkNode* header)
{
if (NULL == header)
{
return;
}
// 辅助指针变量
struct MyLinkNode* pCurrent = header->next;
while (pCurrent != NULL)
{
// 先保存当前节点的下一个节点地址
struct MyLinkNode* pNext = pCurrent->next;
//释放当前节点内存
cout << "节点" << pCurrent->data << "被销毁" << endl;
free(pCurrent);
//指针向后移动
pCurrent = pNext;
}
}
//清空--只保留头节点
void Clear_LinkList(struct MyLinkNode* header)
{
if (NULL == header)
{
return;
}
// 辅助指针变量
struct MyLinkNode* pCurrent = header->next;
while (pCurrent != NULL)
{
// 先保存当前节点的下一个节点地址
struct MyLinkNode* pNext = pCurrent->next;
//释放当前节点内存
free(pCurrent);
//pCurrent指向下一个节点
pCurrent = pNext;
}
header->next = NULL;
}
主程序TestLink.cpp
#include<iostream>
using namespace std;
#include"LinkList.h"
#include<string>
void test()
{
//初始化链表 100 200 666 300 400 500 600
struct MyLinkNode* header = MyInit_LinkList();
//打印链表
MyForeach_LinkList(header);
//插入数据
InsertByValue_LinkList(header, 200, 666);
cout << "--------------------------" << endl;
//打印链表
MyForeach_LinkList(header);
//清空链表
Clear_LinkList(header);
cout << "--------------------------" << endl;
MyForeach_LinkList(header);
InsertByValue_LinkList(header, 1000, 111);
InsertByValue_LinkList(header, 1000, 211);
InsertByValue_LinkList(header, 1000, 311);
InsertByValue_LinkList(header, 1000, 411);
cout << "--------------------------" << endl;
MyForeach_LinkList(header);
//删除deValue
RemoveByValue_LinkList(header, 311);
cout << "--------------------------" << endl;
MyForeach_LinkList(header);
RemoveByValue_LinkList(header, 211);
cout << "--------------------------" << endl;
MyForeach_LinkList(header);
//销毁链表
Destroy_LinkList(header);
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}