王道数据结构实践代码----单链表的实现(C语言版)
前言
日期:2021年8月26日
书籍:王道2021年数据结构考研复习指导
代码内容:实现单链表的实现,包括初始化,插入新元素,删除新元素,输出,查询
代码难点
1.C语言的指针和C++的引用转换
…
指针我太阳你个**
简而言之,王道书上的单链表声明和初始化是以C++为模板的,C语言无法直接使用,需要做一定的转换,介于我指针学的也不是很好,就不说这中间的转换过程和原理了,日后有闲暇了再慢慢研究
2.头插法和尾插法的区别,带头指针和不带头指针的区别
引入头结点后,可以带来两个优点:
①由于第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表的其他位置上的操作一致,无须进行特殊处理。
②无论链表是否为空,其头指针都指向头结点的非空指针(空表中头结点的指针域为空)因此空表和非空表的处理也就得到了统一。
所以,没事儿写代码就把头指针带着吧
头插法vs尾插法
采用头插法建立单链表时,读入数据的顺序与生成的链表中的元素的顺序是相反的。
头插法建立单链表的算法虽然简单,但生成的链表中结点的次序和输入数据的顺序不一致。若希望两者次序一致,则可采用尾插法。该方法将新结点插入到当前链表的表尾,为此必须增加个尾指针r,使其始终指向当前链表的尾结点.
各功能代码
C语言自定义bool操作
//C语言自定义bool操作
#define bool char
#define false 0
#define true 1
单链表结构体定义
/*数据元素类型*/
typedef int ElemType;
/*单链表结构体定义*/
typedef struct LNode //定义单链表结点类型
{
ElemType data; //每个结点存放一个数据元素
struct LNode *next; //指针指向下一节点
}LNode,*LinkList;
/*
上面的代码等价于
typedef struct Lnode Lnode;
typedef struct Lnode * Linklist;
*/
//LinkList L; //声明一个指向单链表第一个结点的指针,这种方法代码可读性更强
/*
上面的代码也可写成:
LNode *L;
//声明一个指向单链表第一个结点的指针,但这种方法可读性不强,
//无法第一时间看出L是指向整个链表的头指针,还是仅仅是个新的结点
*/
链表初始化函数
LinkList ListInit()
{
//[1]申请一块LinkList类型的存储空间给L
LinkList L = (LinkList)malloc(sizeof(LinkList));
//[2]设置L的指针域为空
L->next = NULL;
//返回L指针
return L;
}
创建新结点函数
//创建新结点
LNode* createNote(int data)
{
//[1]为新节点申请空间
LNode* newNode = (LNode*)malloc(sizeof(LNode));
//[2]如果内存满了,则分配失败,返回0
if(newNode == NULL)
{
printf("分配结点失败,请检查内存!");
return NULL;
}
//[3]为新节点的数据域和指针域分别赋值
newNode->data = data;
newNode->next = NULL;
//[4]返回新节点的指针
return newNode;
}
头插法&尾插法
//头插法
bool ListHeadInsert(LinkList L,ElemType data)
{
//[1]调用创建新节点函数,为其赋值
LNode* newNode = createNote(data);
//[2]先给新节点的指针域赋值(指向原来链表的第一个节点)
newNode->next = L->next;
//[3]再让头结点指向新结点
L->next = newNode;
//[4]返回true,表示插入成功
return true;
}
//尾插法(不带尾指针的尾插法,因此每次插入新元素都需要遍历列表,所以时间复杂度为O(n))
bool ListTailInsert(LinkList L,ElemType data)
{
//[1]申请新节点
LNode* newNode = createNote(data);
//[2]生成工具指针
LNode* p = L->next;
//[3]遍历链表,找到最后的元素,用工具指针指向它
while (p->next != NULL)
{
p = p->next;
}
//[4]尾插入新节点
newNode->next = NULL;
p->next = newNode;
}
查询
//按序号查找节点值
LNode *GetElem(LinkList L,int i)
{
//[1]设置一个变量计数
int j = 1;
//[2]设置待返回的结点p,开始指向第一个结点
LNode *p = L->next;
//[3]检查参数
if(i == 0) {
p = L;