系列文章目录
数据结构——顺序表的C语言代码实现
数据结构——八种链表的C语言代码实现
数据结构——栈的C语言代码实现
前言
该篇文章是剩余六个链表之一的c语言代码实现,因为前两篇(单向不带头非循环与双向带头循环)中已经介绍过了链表中常见的接口函数和基础知识,故该篇文章只放代码,难点请看注释
一、List.h
代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
typedef int ListDataType;
typedef struct ListNode
{
ListDataType data;
struct ListNode* next;
}LN;
//初始化头结点
void ListInit(LN** phead);
//尾插法
void ListPushBack(LN* phead, ListDataType x);
//尾删法
void ListPopBack(LN* phead);
//头插法
void ListPushFront(LN* phead, ListDataType x);
//头删法
void ListPopFront(LN* phead);
//查找节点
LN* ListFind(LN* phead, ListDataType x);
//在指定节点前插入
void ListInsertFront(LN* phead, ListDataType x, ListDataType num);
//在指定节点后插入
void ListInsertBack(LN* phead, ListDataType x, ListDataType num);
//删除节点
void ListDeleteNode(LN* phead, ListDataType x);
//改变节点
void ListChangeNode(LN* phead, ListDataType x, ListDataType num);
//删除链表
void ListFree(LN* phead);
//打印链表
void ListPrint(LN* phead);
二、List.c
代码如下:
#include"List.h"
//定义全局的尾指针,便于接口函数实现
//注意该指针必须在这个文件里定义
LN* tail = NULL;
//初始化头结点
void ListInit(LN** phead)
{
*phead = (LN*)malloc(sizeof(LN));
tail = *phead;
}
//尾插法
void ListPushBack(LN* phead, ListDataType x)
{
if (phead->next == NULL)
{
printf("error\n");
return;
}
LN* tem = (LN*)malloc(sizeof(LN));
tem->data = x;
tem->next = NULL;
tail->next = tem;
tail = tem;
}
//尾删法
void ListPopBack(LN* phead)
{
if (phead->next == NULL)
{
printf("error\n");
return;
}
LN* tem = phead;
while (tem->next->next != NULL)
{
tem = tem->next;
}
free(tail);
tem->next = NULL;
tail = tem;
}
//头插法
void ListPushFront(LN* phead, ListDataType x)
{
LN* tem = (LN*)malloc(sizeof(LN));
tem->data = x;
tem->next = phead->next;
phead->next = tem;
}
//头删法
void ListPopFront(LN* phead)
{
LN* tem = phead->next->next;
free(phead->next);
phead->next = tem;
}
//查找节点
LN* ListFind(LN* phead, ListDataType x)
{
LN* tem = phead->next;
while (tem)
{
if (tem->data == x)
{
return tem;
}
tem = tem->next;
}
return NULL;
}
//在指定节点前插入
void ListInsertFront(LN* phead, ListDataType x, ListDataType num)
{
LN* tem = ListFind(phead, x);
if (tem == NULL)
{
printf("链表中没有%d\n", x);
return 0;
}
else
{
LN* insert = (LN*)malloc(sizeof(LN));
insert->data = num;
LN* preinsert = phead;
while (preinsert->next != tem)
{
preinsert = preinsert->next;
}
insert->next = tem;
preinsert->next = insert;
}
}
//在指定节点后插入
void ListInsertBack(LN* phead, ListDataType x, ListDataType num)
{
LN* tem = ListFind(phead, x);
if (tem == NULL)
{
printf("链表中没有%d\n", x);
return 0;
}
else
{
LN* insert = (LN*)malloc(sizeof(LN));
insert->data = num;
if (tem != tail)
{
insert->next = tem->next;
tem->next = insert;
}
//注意此时需要判断所要插入的位置是否是尾节点
//因为此时可能会设计tail的更改,而且print函数的循环条件与tail的值有关
//如果要插入到尾指针之后,却只是使用
//insert->next = tem->next;
//tem->next = insert;
//会造成tail指向倒数第二个节点,而不是尾节点
else
{
tail->next = insert;
tail = insert;
}
}
}
//删除节点
void ListDeleteNode(LN* phead, ListDataType x)
{
LN* tem = ListFind(phead, x);
if (tem == NULL)
{
printf("链表中没有%d\n", x);
return 0;
}
else
{
if (tem == tail)
{
LN* pretail = phead;
while (pretail->next != tail)
{
pretail = pretail ->next;
}
free(tail);
pretail->next = NULL;
tail = pretail;
}
else
{
LN* pretem = phead;
while (pretem->next != tem)
{
pretem = pretem->next;
}
pretem->next = tem->next;
free(tem);
}
}
}
//改变节点
void ListChangeNode(LN* phead, ListDataType x, ListDataType num)
{
LN* tem = ListFind(phead, x);
if (tem == NULL)
{
printf("链表中没有%d\n", x);
return 0;
}
else
{
tem->data = num;
}
}
//删除链表
void ListFree(LN* phead)
{
LN* tem = phead;
while (tem)
{
LN* next = tem->next;
free(tem);
tem = next;
}
}
//打印链表
void ListPrint(LN* phead)
{
LN* tem = phead->next;
while (tem != tail->next)
{
printf("%d->", tem->data);
tem = tem->next;
}
printf("NULL\n");
}
三、test.c
代码如下:
#include"List.h"
int main()
{
LN* plist = NULL;
ListInit(&plist);
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushFront(plist, 4);
ListPushFront(plist, 4);
ListPushFront(plist, 4);
ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
/*LN* tem=ListFind(plist, 4);
printf("%d %p", tem->data, tem);*/
ListInsertFront(plist, 2, 6);
ListPrint(plist);
ListInsertBack(plist, 2, 6);
ListPrint(plist);
ListDeleteNode(plist, 2);
ListPrint(plist);
ListChangeNode(plist, 4, 10);
ListPushBack(plist, 12);
ListPrint(plist);
ListChangeNode(plist, 12, 13);
ListPrint(plist);
ListDeleteNode(plist, 13);
ListPrint(plist);
ListFree(plist);
return 0;
}
总结
相信大家在认真实现最简单和最复杂的两种链表之后,便练就了闭眼敲链表的无上神功!
但学习贵在坚持,剩余六种链表的实现过程略感无趣,却依然要坚持全部手敲。加油!