什么是链表结构:
链表结构是由许多节点构成的,每个节点都包含两部分:
- 数据部分:保存该节点的实际数据。
- 地址部分:保存的是下一个节点的地址。
链表的特点:
- 结点在存储器中的位置是任意的,即逻辑上相邻的数 据元素在物理上不一定相邻
- 访问时只能通过头指针进入链表,并通过每个结点的 指针域向后扫描其余结点,所以寻找第一个结点和最后一 个结点所花费的时间不等
链表的优点:
- 数据元素的个数可以自由扩充 、插入、删除等操作不必移动数据,只需 修改链接指针,修改效率较
链表的缺点:
- 存储密度小 、存取效率不高,必须采用顺序存取,即存 取数据元素时,只能按链表的顺序进行访问
在进行链表操作时,首先需要定义一个头指针变量(head表示),该指针变量指向链表的第一个节点。
最后一个节点不再指向其他节点(单链表),称为表尾。
单链表:
- 像上面的链式结构一样,每个节点包含一个指针指向下一个节点。
链表数据表示:
typedef struct
{
char key[10]; //关键字
char name[20];
int age;
}Data; //数据节点类型
typedef struct Node
{
Data nodeData; //数据域
struct Node *nextNode; //指针域
}CLType;
添加节点步骤:
- 单链表节点添加可以在任意位置插入,且不需要移动数据元素,只需修改链表的指针域即可。插入时间复杂度为O(1)。
- 首先分配内存空间,保存新增节点。
- 从头指针 head 开始逐个检查,直到找到要插入的位置。
- 将插入节点前一个节点指针指向要插入的节点地址,在修改当前节点指针域指向下一个节点地址,把链表连接起来。
- 若插入位置为表尾,则把节点指针域置为空(NULL)。
添加链表实现代码:
//在链表尾添加节点
CLType *CLAddEnd(CLType *head, Data nodeData)
{
CLType *node, *htemp;
node = new CLType;
if (!node)
{
std::cout << "内存申请失败." << std::endl;
return NULL;
}
else
{
node->nodeData = nodeData; //保存数据
node->nextNode = nullptr; //将节点置为NULL,当前插入位置为表尾
if (head == nullptr)
{
head = node;
return head;
}
htemp = head;
while (htemp->nextNode != nullptr) //查找链表的末尾
{
htemp = htemp->nextNode;
}
htemp->nextNode = node; //修改指针域把链表连接起来
return head;
}
}
在链表头插入头节点步骤:
1 .首先分配内存空间,保存新增节点。
2 .使新增节点指向头指针 head所指向的节点。
3 .然后使头指针 head指向新增节点。
//在链表头插入节点
CLType *CLAddFirst(CLType *head, Data nodedata)
{
CLType *node = new CLType;
if (!node) //内存分配失败
{
std::cout << "内存申请失败!" << std::endl;
return nullptr;
}
else
{
node->nodeData = nodedata; //保存数据
node->nextNode = head; //指向头指针所指节点
head = node; //头指针指向新增节点
return head;
}
}
查找节点:
//查找节点
CLType *CLFindNode(CLType *head, char *key)
{
CLType *htemp;
htemp = head; //保存链表头指针
while (htemp) //若节点有效,则进行循环查找
{
if (strcmp(htemp->nodeData.key, key) == 0) //若节点关键字与传入关键字相同
{
return htemp; //return 该节点指针
}
htemp = htemp->nextNode; //进行迭代查找
}
return nullptr; //不存在,返回空指针
}
随机插入节点步骤:
1 .首先分配内存,保存新增节点。
2 .找到要插入的逻辑位置,也就是要插入某两个节点之间。
3 .修改插入位置的节点指针,使其指向新增节点,而使新增节点指向原插入位置所指向的节点
//随机插入节点
CLType *CLinsertNode(CLType *head, char *findkey, Data nodedata)
{
CLType *node, *nodetemp;
node = new CLType; //分配保存的节点内存
if (!node) //内存分配失败
{
std::cout << "内存申请失败." << std::endl;
return nullptr;
}
node->nodeData = nodedata; //保存节点中的数据
nodetemp = CLFindNode(head, findkey);
if (nodetemp) //若找到要插入的节点
{
node->nextNode = nodetemp->nextNode; //新插入节点指向关键节点的下一节点
nodetemp->nextNode = node; //设置关键节点指向新插入节点
}
else
{
std::cout << "未找到正确的插入位置." << std::endl;
delete node; //释放内存
}
return head; //返回头指针
}
删除节点步骤:
1 .查找要删除的节点
2 .使前一节点指向当前节点下一节点
3 .删除节点
//删除节点
int CLDeleteNode(CLType *head, char *key)
{
CLType *node, *htemp; //node保存删除节点的前一节点
htemp = head;
node = head;
while (htemp)
{
if (strcmp(htemp->nodeData.key, key) == 0) //找到关键字,执行删除操作
{
node->nextNode = htemp->nextNode; //使前一节点指向当前节点的下一节点
delete htemp; //释放内存
return 1;
}
else
{
node = htemp; //指向当前节点
htemp = htemp->nextNode; //指向下一节点
}
}
return 0; //删除失败
}
计算链表长度
//计算链表长度
int CLLength(CLType *head)
{
CLType *htemp;
int len = 0;
htemp = head;
while (htemp) //遍历链表
{
len++; //累计节点数
htemp = htemp->nextNode; //处理下一节点
}
return len; //return 节点数
}
显示所有节点:
//显示所有节点
void CLAllNode(CLType *head)
{
CLType *htemp;
Data nodeData;
htemp = head;
std::cout << "当前链表共有: " << CLLength(head) << "个节点,链表数据如下: "<<std::endl;
while (htemp)
{
nodeData = htemp->nodeData;
std::cout << "节点: " << nodeData.key << " " << nodeData.name << " " << nodeData.age << std::endl;
htemp = htemp->nextNode;
}
}
main 函数:
int main()
{
CLType *node, *head = nullptr;
Data nodeData;
char key[10], findkey[10];
cout << "请输入链表中的数据,格式为: 关键字 姓名 年龄 " << endl;
do {
cin >> nodeData.key;
if (strcmp(nodeData.key, "0") == 0)
break; //若输入为0,则退出
else
{
cin >> nodeData.name>>nodeData.age;
head = CLAddEnd(head, nodeData);
}
} while (1);
CLAllNode(head);
cout << " 输入插入位置的关键字: ";
cin >> findkey;
cout << "输入插入节点的数据(关键字 姓名 年龄 ): \n";
cin >> nodeData.key >> nodeData.name >> nodeData.age;
head = CLinsertNode(head, findkey, nodeData);
CLAllNode(head);
cout << "删除节点,输入要删除的关键字: " << endl;
cin >> key;
CLDeleteNode(head, key);
CLAllNode(head);
cout << "查找关键字,输入要查找的关键字: " << endl;
cin >> key;
node = CLFindNode(head, key);
if (node)
{
nodeData = node->nodeData;
cout << "关键字" << key << " 对应的节点为" << key << nodeData.key << nodeData.name << nodeData.age;
}
else
{
cout << "未找到关键字";
}
cout << endl;
system("pause");
return 0;
}
测试结果: