数据结构----链表算法题目

1.移除链表的元素

这个题目我们有多种解决方案

(1)思路A:遍历整串数据,如果是我们想要删除的数据,就让这个数字后面的数字全部向前移动直到整传数字全部遍历完成;这个方法的时间复杂度是N的平方;

(2)思路B:时间复杂度的优化:我们新建一个数组temp,在原来的数组里面找到不是val的数字,放到temp数组里面,最后把temp数组赋值给原来的数组,这样时间复杂度就是两次遍历,即2N,因为在计算时间复杂度的时候,常数是忽略的,因此这个时间复杂度就是O(N),这个做法就是拿空间换取时间;(代码的解法就是这个)

(3)思路C:这个做法就是利用两个指针的移动,分别定义两个指针src和dest指针,我们让开始的时候2个指针都指向我们的第一个数据,然后是src不断地向后移动,如果src指向的数据是val就跳过,不是val就让src指向的值赋值给dest,这个时候两个指针都要进行向后移动一位,最后我们可以发现当这个时候的dest前面的所有数据正好是我们想要的;这个时候相当于只遍历了一次,时间复杂度就是O(N),这个是正经的N,思路B是2N简化的N,因此,这个解法的效率是最高的;

(1)我们自己先是利用typedef对结构体重新定义;

(2)定义了一个pcur指针,指向的是链表的头部,接下来进行遍历,如果我们遍历到的数据和val不相同就会进入循环,循环里面分为两种情况,链表是空的和链表不是空的,链表是空的话,就直接把我们pcur指向链表的头部和尾部(这里的头部就是尾部);

(3)如果链表不是空的话就需要一个一个地进行遍历,因为我们的符合条件的要放在一个新的链表里面,而且是尾插到新的链表里面去;

(4)当我们全部全部遍历完之后,如果最后的一个元素是val,就需要把前面的一个节点的next设置为空指针,否则她还是能找到下一个元素的;

2.反转链表

(1)我们可以有多种方法解决这个问题,例如我们可以新建链表把1取出来,作为一个头结点,再把2取出来,在链表里面进行头插,依次进行下去,我们就可以解决这个链表的反转问题;

(2)我们这里提供的方法是设置3个指针,对链表进行处理,n1,n2,n3这三个指针,n1指向的是空指针,n2指向的是链表的头部,n3指向的是链表的第二个位置,我们进行的操作就是对链表进行:把2的指针指向1,这个时候把n1挪到n2的位置,n2挪到n3的位置,n3挪到自己的下一个节点的位置,我们循环往复进行这样的操作,但是到链表的最后一个结点的时候,n1指向倒数第二个元素,n2指向最后的一个元素,n3指向的就是空位置,这个时候我们无法对n3进行n3=n3->next的操作,因此我们进行判断n3本身是否是空的,是空的我们在进行n3=n3->next的操作。

3.链表的中间节点

(1)这里提供两种方案,第一种就是遍历整个链表,然后进行计数,我们得到的count就是链表里面的结点的全部个数,我们使用count/2作为我们想要查找的元素的下标;

(2)我们这个代码利用的是快慢指针的思路:我们首先介绍一下:快慢指针就是说快指针是一次向后移动两个节点,慢指针就是一次跳过一个节点,当我们的fast指向的是空(奇数个节点),或者是fast->next指向空(偶数个节点),我们就找到了,slow指向的位置就是我们的中间节点;读者可以自行画图尝试;

(3)我们这里要特别说明一下,while循环里面的判断条件,fasr&&fast->next不能是空的,这两个判断的条件是不能换的,如果是偶数个节点,我们写作fast->next&&fast(这个写法是错误的),我们的偶数个节点,最后的fast->next相当于是对空指针解引用,这个时候的话程序一定会报错;但是我们如果先进行判断fast如果是空的话就会直接跳出循环,因为是&&连接符,就不会进行右边的判断了,这个时候是不会报错的。

4.合并两个有序的链表

(1)我们要首先进行创建两个新的链表;进行判空,如果一个是空的,直接返回另外的一个链表就行了;

(2)我们进行定义两个指针,分别指向两个链表的的头部,当两个链表都没有遍历完成的时候,进入循环,循环里面就是让li,l2指针指向的链表里面的元素进行比较,小的元素添加到新的链表的尾部,只要有一个遍历完成就会跳出循环,剩下的那个没有遍历完成的直接追加到新链表的后面

(3)另外的解法:上面的解法判断的时候,是重复的,我们优化一下解决方案:因为我们上面的做法是创建了两个新的链表之后就把头和尾全部设置为NULL,因此可能会出现为空的链表的情况,我们下面的解法不让他为空:

(4)具体如何做呢:我们使用动态内存管理函数malloc开辟空间,这个时候头部的节点和尾部的节点就指向了确定的地址(可能我们暂时不知道),但是这个时候就不可能是空的,我们不需要进行判断了,这个新开辟的链表长这个样子:

(5)这个时候,头尾指针指向了有效的地址,我们把链表的数据插入到2个之间;我们动态开辟的内存要进行释放,释放之后我们就找不到需要返回的头结点了,因此我们定义了一个临时变量ret把头节点后面的那个地址存起来(因为头节点是我们开辟空间的时候编译器加的,我们的链表数据是从第二个位置开始的),我们释放之后置空,返回这个的第二个位置的地址(也就是我们定义的临时变量ret);后面我们会学到,这个头部节点叫做哨兵位,这种链表叫做带头链表。

上一篇:Unity让地图素材遮挡人物