单链表
一、单链表的设计
1.单链表的结构定义:
typedef struct Node{
int data;//数据域
struct Node* next;//后继指针
}Node,*List;
2.单链表的结构示意图:
3.单链表的最后一个节点的next域为NULL;
4.为什么要有一个头节点?
- 简单方便,不用传二级指针
二、单链表的实现
- list.cpp
-
- 头插,尾插与按值删除
//头插
bool Insert_head(List plist, int val){
assert(plist != NULL);
Node*p = (Node*)malloc(sizeof(Node));
assert(p != NULL);
p->data = val;
p->next = plist->next;
plist->next = p;
return true;
}
//尾插
bool Insert_tail(List plist, int val){
assert(plist != NULL);
Node*p = (Node*)malloc(sizeof(Node));
assert(p != NULL);
p->next = val;
Node*q = plist;
for(; q->next != NULL; q = q->next){
;
}
p->next = q->next;
q->next = p;
return true;
}
//判空
bool IsEmpyt(List plist){
assert(plist != NULL);
return plist->next == NULL;
}
//删除第一个val的值
bool DelVal(List plist, int val){
assert(plist != NULL);
if(IsEmpyt(plist) == NULL){
return false;
}
Node*p = GetPrio(plist, val);
Node*q = p->next;
p->next = q->next;
free(q);
}
//返回key的前驱地址,如果不存在返回NULL
Node* GetPrio(List plist, int key){
assert(plist != NULL);
Node*p = plist;
for(; p->next != NULL; p = p->next){
if(p->next->data == val){
return p;
}
return NULL;
}
-
- 整合:
#include "list.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
// 初始化链表,确保链表头指针不为空
void InitList(List plist) {
assert(plist != NULL);
plist->next = NULL; // 将头节点的指针置为空
}
// 头插法插入节点
bool Insert_head(List plist, int val) {
Node* p = (Node*)malloc(sizeof(Node));
assert(p != NULL);
if (plist == NULL)
return false;
p->data = val;
p->next = plist->next; // 先连接后面的
plist->next = p; // 头节点指向新节点
return true;
}
// 尾插法插入节点
bool Insert_tail(List plist, int val) {
Node* p = (Node*)malloc(sizeof(Node));
assert(p != NULL);
if (plist == NULL)
return false;
p->data = val;
p->next = NULL;
Node* tail = plist;
while (tail->next != NULL) {
tail = tail->next; // 移动到链表末尾
}
tail->next = p; // 将新节点连接到末尾
return true;
}
// 在链表的指定位置(pos)(0,1...)插入节点(val)
bool Insert(List plist, int pos, int val) {
// 检查链表是否为空
if (plist == NULL)
return false;
if (pos < 0 || pos > GetLength(plist)) {
return false;
}
Node* p = (Node*)malloc(sizeof(Node));
assert(p != NULL);
p->data = val;
Node* current = plist;
int count = 0;
// 找到要插入位置的前一个节点
while (current != NULL && count < pos) {
current = current->next;
count++;
}
if (current == NULL) {
free(p); // 未找到位置,释放新节点
return false;
}
// 插入新节点
p->next = current->next;
current->next = p;
return true;
}
// 判断链表是否为空
bool IsEmpty(List plist) {
return plist->next == NULL; // 如果头节点的下一个节点为空,链表为空
}
// 获取链表节点的个数
int GetLength(List plist) {
int count = 0;
Node* current = plist->next;
while (current != NULL) {
count++;
current = current->next;
}
return count;
}
// 在链表中查找第一个包含指定值的节点
Node* Search(List plist, int key) {
Node* current = plist->next;
while (current != NULL) {
if (current->data == key)
return current; // 找到节点后返回节点指针
current = current->next;
}
return NULL; // 未找到时返回NULL
}
// 删除链表指定位置(pos)(1,2,3...)的节点
bool DelPos(List plist, int pos) {
if (IsEmpty(plist))
return false;
Node* current = plist;
int count = 0;
// 找到要删除位置的前一个节点
while (current->next != NULL && count < pos - 1) {
current = current->next;
count++;
}
if (current->next == NULL) {
return false; // 未找到位置
}
Node* temp = current->next;
current->next = temp->next;
free(temp);
return true;
}
// 删除第一个包含指定值(val)的节点
bool DelVal(List plist, int val) {
if (IsEmpty(plist))
return false;
Node* current = plist;
while (current->next != NULL) {
if (current->next->data == val) {
Node* temp = current->next;
current->next = temp->next;
free(temp);
return true;
}
current = current->next;
}
return false;
}
// 返回指定值的前驱节点地址
Node* GetPrio(List plist, int key) {
Node* current = plist;
while (current->next != NULL && current->next->data != key) {
current = current->next;
}
if (current->next == NULL || current == plist) {
return NULL; // 未找到前驱节点
}
return current;
}
// 返回指定值的后继节点地址
Node* GetNext(List plist, int key) {
Node* current = Search(plist, key);
if (current != NULL && current->next != NULL) {
return current->next;
}
return NULL; // 未找到后继节点
}
//返回key的后继地址,如果不存在返回NULL;
Node* GetNext(List plist, int key)
{
assert(plist != NULL);
if (plist == NULL)
return NULL;
Node* p = Search(plist, key);
if (p == NULL)
return NULL;
return p->next;
}
// 输出链表的所有节点数据
void Show(List plist) {
Node* current = plist->next;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
// 销毁整个链表
void Destroy(List plist) {
Node* current = plist;
while (current->next != NULL) { // 遍历 ?????????????
Node* temp = current;
current = current->next;
free(temp);
}
// 不需要将plist设置为NULL
}
三、总结
1.特点
头插,头删 时间复杂度是O(1)
尾插,尾删 时间复杂度是O(n)
2.考点
头插,尾插,按值删除