目录
链表的实现:
1.先起别名,提高后续代码的开发效率,增加代码的可读性
2.定义链表结点的结构体类型
3.定义对链表的主要操作方法
4.对链表进行测试操作
测试代码总览
合并链表:
5.操作链表的方法补充:
1.合并两个链表
2.合并两个链表,并根据其数据大小进行排序
#include
#include
// C语言中,结构体类型名前的struct不可以省略!!!
// C++可以省略!
// typedef 已知类型 类型别名
typedef struct LLNode* LinkedList; // LinkedList == struct LLNode* 链表结点指针
// --> 使用别名后,无需再写struct
typedef int elemType; // 链表数据类型
// 定义链表结点
struct LLNode
{
elemType data;
LinkedList next;
};
// 1.初始化空链表/生成新结点
LinkedList makeEmpty()
{
LinkedList head = (LinkedList)malloc(sizeof(struct LLNode)); // 用头指针指向申请的新空间
head->next = NULL;
return head;
}
// 2.查找第n个元素,返回第n个元素结点
LinkedList find_nth(int n, LinkedList head)
{
if (n < 1) // 输入错误
{
return NULL;
}
LinkedList p = head->next; // 拿到第一个结点
int i = 1;
while (i < n && p != NULL)
{
p = p->next;
i++;
}
if (p == NULL) // 找不到
{
return NULL;
}
else // 找到了
{
return p;
}
}
// 3.找到值为x的元素第一次出现的位置,返回位置
int find(elemType x, LinkedList head)
{
LinkedList p = head->next; // 拿到第一个结点
int count = 1;
while (p != NULL && p->data != x)
{
p = p->next;
count++;
}
if (p == NULL) // 找不到值为x的元素
{
return NULL;
}
else // 找到值为x的元素
{
return count;
}
}
// 4.1在位置pos插入值为x的新结点
void insert(elemType x, int pos, LinkedList head)
{
if (pos < 1) // 输入位置不符规范
{
printf("位置输入错误!\n");
return;
}
LinkedList new_node = NULL;
if (pos == 1) // 插入到第一个位置的情况
{
new_node = makeEmpty();
new_node->data = x;
new_node->next = head->next;
head->next = new_node;
}
else // 插入到其他位置
{
int i = 0;
while ((++i) != pos && head->next != NULL) // 如果pos大于链表长度,则自动改为尾插
{
head = head->next;
}
new_node = makeEmpty();
new_node->data = x;
new_node->next = head->next;
head->next = new_node;
}
}
// 4.2尾插
void backInsert(elemType x, LinkedList head)
{
LinkedList p = head; // 从头指针开始往后遍历(链表可能为空,此时没有第一个结点)
LinkedList new_node = makeEmpty(); // 创建新结点
new_node->data = x;
while (p->next != NULL) // 遍历到链表尾部进行插入
{
p = p->next;
}
p->next = new_node;
}
// 5.删除位置pos的结点
LinkedList deleteNode(int pos, LinkedList head)
{
if (pos < 1)
{
printf("位置输入错误!\n");
return NULL;
}
if (pos == 1) // 删除第一个结点
{
LinkedList p = head->next; // 拿到第一个结点
if (p != NULL)
{
head->next = p->next;
free(p);
return head;
}
else
{
return NULL;
}
}
else // 删除其余结点
{
LinkedList p = find_nth(pos - 1, head); // 找到要删除结点的前一个结点
if (p == NULL || p->next == NULL)
{
printf("第%d个结点不存在!\n", pos);
return NULL;
}
else
{
LinkedList temp = p->next;
p->next = p->next->next;
free(temp);
printf("删除第%d个结点成功!\n", pos);
return head;
}
}
}
// 6.返回链表的长度
int length(LinkedList head)
{
LinkedList p = head->next;
int count = 0;
while (p)
{
p = p->next;
count++;
}
return count;
}
// 7.输出链表
void print(LinkedList head)
{
if (head->next == NULL) // 链表为空
{
printf("链表为空!\n\n");
return;
}
printf("打印链表:");
LinkedList p = head;
while (p->next != NULL)
{
p = p->next;
printf("%d ", p->data);
}
printf("\n\n");
}
分布展示测试效果
// 初始化链表
LinkedList head = makeEmpty();
// 4.2尾插
backInsert(101, head);
backInsert(102, head);
backInsert(103, head);
// 7.输出链表
print(head);
// 6.返回链表的长度
printf("链表长度为:%d\n", length(head));
system("pause");
// 4.1在位置pos插入值为x的新结点
insert(104, 1, head);
insert(105, 3, head);
insert(106, 1, head);
// 5.删除位置pos的结点
deleteNode(2, head);
// 2.返回第n个元素结点
LinkedList temp = find_nth(4, head); // test1
if (temp != NULL)
{
printf("第4个结点的数据为:%d\n", temp->data);
}
else
{
printf("未找到第4个结点!\n");
}
temp = find_nth(8, head); // test2
if (temp != NULL)
{
printf("第8个结点的数据为:%d\n", temp->data);
}
else
{
printf("未找到第8个结点!\n");
}
// 3.找到值为x的元素第一次出现的位置
int pos = find(103, head); // test1
if (pos != NULL)
{
printf("第一次出现值为103的结点位置为:%d\n", pos);
}
else
{
printf("未找到值为103的结点!\n");
}
pos = find(108, head); // test2
if (pos != NULL)
{
printf("第一次出现值为108的结点位置为:%d\n", pos);
}
else
{
printf("未找到值为108的结点!\n");
}
// 测试代码
int main()
{
// 初始化链表
LinkedList head = makeEmpty();
// 4.2尾插
backInsert(101, head);
backInsert(102, head);
backInsert(103, head);
// 4.1在位置pos插入值为x的新结点
insert(104, 1, head);
insert(105, 3, head);
insert(106, 1, head);
// 5.删除位置pos的结点
deleteNode(2, head);
// 7.输出链表
print(head);
// 2.返回第n个元素结点
LinkedList temp = find_nth(4, head); // test1
if (temp != NULL)
{
printf("第4个结点的数据为:%d\n", temp->data);
}
else
{
printf("未找到第4个结点!\n");
}
temp = find_nth(8, head); // test2
if (temp != NULL)
{
printf("第8个结点的数据为:%d\n", temp->data);
}
else
{
printf("未找到第8个结点!\n");
}
// 3.找到值为x的元素第一次出现的位置
int pos = find(103, head); // test1
if (pos != NULL)
{
printf("第一次出现值为103的结点位置为:%d\n", pos);
}
else
{
printf("未找到值为103的结点!\n");
}
pos = find(108, head); // test2
if (pos != NULL)
{
printf("第一次出现值为108的结点位置为:%d\n", pos);
}
else
{
printf("未找到值为108的结点!\n");
}
// 6.返回链表的长度
printf("链表长度为:%d\n", length(head));
system("pause");
return 0;
}
// 8.1合并两个链表
LinkedList mergeLinkedList(LinkedList h1, LinkedList h2) // 将h2接到h1后面
{
LinkedList p = h1;
while (p->next != NULL) // 遍历到链表尾部进行插入
{
p = p->next;
}
p->next = h2->next;
return h1;
}
// 8.2合并两个链表,并根据其数据大小进行排序
LinkedList mergeLinkedListByAsc(LinkedList h1, LinkedList h2) // 将h2接到h1后面
{
// 先进行合并
LinkedList p = h1;
while (p->next != NULL) // 遍历到链表尾部进行插入
{
p = p->next;
}
p->next = h2->next;
// 再进行排序
LinkedList pre_p; // 双指针便于操作
for (int i = 0; i < length(h1) - 1; i++)
{
// 指针重置
pre_p = h1;
p = h1->next;
while (p != NULL && p->next != NULL) // 遍历所有结点 (p != NULL为结点移动后,无后继元素,此时p后移为NULL)
{
if (p->next->data < p->data)
{
pre_p->next = p->next;
p->next = pre_p->next->next;
pre_p->next->next = p;
pre_p = pre_p->next; // 移动前指针
}
// 双指针后移
pre_p = pre_p->next;
p = p->next;
}
}
return h1;
}