如果对参数的修改结果需要带回来
就需要传入这种引用型的参数
不给数据元素设置初值的话,由于系统中遗留下来的脏数据,会导致数组中,出现一些奇怪的数据
malloc函数的原理:
malloc函数所实现的事情是会申请一整片的连续的内存空间,这一整片连续的存储空间一定会有一个起始地址,所以malloc函数执行结束之后他会返回(return)一个指向这一整片存储空间开始地址的指针 ,由于这一整片空间是用于存放这一个一个的数据元素的,所以在这个地方,我们需要把malloc函数返回的指针,把它强制转换成我们所定义的这个数据元素的指针类型
我们把他赋给顺序表中的data这个指针变量,也就是说data这个指针是指向了这一整片存储空间的起始地址,
而malloc函数到底需要申请多大的存储空间的地址,我们就用
(elemtype*)malloc(sizeof(elemtype)*initsize)
两种方法传递地址
法一:
法二:
定义一个顺序表,顺序表的元素类型是int型,data这个指针指向顺序表中第一个元素
初始化一个动态分配实现的顺序表,
初始化length的长度为0,防止垃圾数据是程序出现混乱
最长长度赋初值为10
当我们想要定义一个新的节点的时候,或者定义一个指向节点的指针的时候,可以类似上方的情况,但是比较繁琐,所以使用typedef关键字数据类型重命名
如
上着等价于先定义一个struct node类型的结构体
然后通过typedef来将struct LNode 更名为LNode
并且用LinkList表示这是一个指向struct LNode的指针。
所以当我们要表示一个单链表的时候,只需要声明一个头指针L,这个头指针指向单链表的第一个结点,而由于各个结点是由next的指针串联起来的,所以只要找到了第一个结点,就相当于我们已经找到了整个单链表。
既然L这个指针是指向了某一个结点,那么我们定义L的时侯,可以用这样的方式来定义
二者等价
,只不过采用后面这种方式来声明头指针的时候,可以让代码的可读性更强
LNode *和LinkList的本质是一样的,不过在此处,返回值的类型被定义为LNode*,它是想强调我返回的是一个结点,而后面的参数L,他想强调的是,此处是一个单链表
想强调结点用LNode *
想强调是一个链表用LinkList
指针p指向了和L相同的位置,也就是头结点,
*p是指针扫描到的当前结点
j是当前p指向的是第几个结点
L指向头结点,头结点是第0个结点(不存数据)
执行第一个循环的目的是要找到第i-1个结点
如果需要前插操作,则需要有一个头指针,有了头指针,通过循环,就可以知道后续所有的结点
只给出了一个e,我们自己malloc了一个新的结点
偷天换日的操作,时间复杂度仅为O(1)
同理操作如下
需要注意的是,e这个参数是引用类型的,他需要被传递到到这个函数的调用者那里
单链表的查找操作
分为按位查找和按值查找
不管是要插入还是删除,都需要先遍历,也就是先要查找,这些都是建立在查找之上的
但是注意,在此处elemtype的类型是int等类型是可以的,而struct类型的结构体不能通 != 来判断
单链表建立的两种方法,分别是头插法或者尾插法
r = s 的意思是
让r指针指向s这个结点,接下来就可以输入下一个数据了
指针相等,意思就是让两个地址相等,也就是让r指针指向的地址与s相等,也就是r指向s指向的位置,也就是尾结点的位置
r这个指针,永远要让他指向表位的这个数据结点
头插法建立单链表和上面的原理类似,只不过是在头结点之后反复增加新的结点
不管是头插法还是尾插法,最好养成一个写代码的好习惯,在申请了一片空间之后,就应该把他初始化
所有的前插操作,都可以转换为后插来实现
通过增加一些条件判断,用来提升代码的健壮性,
如图所示
右边上半部分代码中,没有增加一些条件判断,所以如果q的后继结点为NULL,则会出现一些问题
如何销毁一个双链表i
双链表的遍历如何实现
在应用场景当中,需要经常对表头或者表尾进行操作的话,那么当使用单链表的时候,可以让单链表的指针L指向最表尾的这个元素,如果这么做的话,当早表尾需要插入删除一个元素的时候,就需要修改L的值。