1、算法面试笔试总结Algorithms and Data Structures 1明确数据结构,单一进行操作1-1单一数据结构1-1-1链表在单数据结构(即在题目中明确提到了某种数据结构,没有掺杂,也没有背景,只是进行某些特定操作)的题型中,链表是一大类,而单链表因为其特定的存储结构和读取方法又成为考查的重点。列举题目如下(注:以下题目的给定Node节点全部为如下定义方式)public class Node public Node next; public object data; 1-1-1-1单链表的反转给定单链表的头节点Node head.给出将此链表反转的方法。public void R
2、everseLinkedList(Node head) /首先,反转后必然head为尾部节点,将head的一份拷贝赋值给一个新的node节点,用于托管旧的链表。 Node nDele = head; /等你将旧链表需要摘取的项加到新链表头部时,需要用另一个node暂时托管旧链表。 Node nNext = null; /此时就将head 置为了新链表的末尾了。 head = null; while (nDele != null) /这几部依次为:先存下当前节点的下一节点用于备份,之后将dele节点指向新链表的头部并且将新链表的头位置前移,同时控制每次循环都能指向后一个节点向前进行。 nNext
3、 = nDele.next; nDele.next = head; head = nDele; nDele = nNext; /至此算法完结。在这个while循环结束时候,就将原来的链表重新接在了新链表上,完成了逆转操作。 1-1-1-2链表相交给定两个单链表,表头分别为head1和head2.判断两个链表是否相交,如果不相交返回null,如果相交,则给出相交的第一个交点。对题目进行简单分析后不难得出,因为链表的特殊存储结构,使得其在存储结构上如果交叉则一定为“Y”型或者为“V”型,不可能为“X”型。所以相交只需求出第一个交点。算法具体实现可以如下public Node FindSameNod
4、e(Node head1, Node head2) if (head1 = null | head2 = null) return null; /两个Node用于托管两个Linkedlist,这样在操作时候不会破坏原有Node地址。 Node tNode1 = head1; Node tNode2 = head2; /用于记录两个链表的长度。 int lHead1 = 0, lHead2 = 0; /用于求出连个链表的长度, while (tNode1 != null) tNode1 = tNode1.next; lHead1+; while (tNode2 != null) tNode2 =
5、 tNode2.next; lHead2+; /到最后都没有相交,必然没有相交。 if (tNode1 != tNode2) return null; /相交了,这时还可以继续从参数提取俩链表首地址。 else tNode1 = head1; tNode2 = head2;/没有这两个赋值,他们的next都为null了。 /先假设两个链表长度不一样,求出他们的长度差。 int f = System.Math.Abs(lHead1 - lHead2); /先判断后循环,小优化。 if (lHead1 lHead2) /使长的链表将长的一部分走完,之后就能一起走到交点。当循环结束,两个链表指针到末
6、尾的长度一样了。 for (int k = 0; k f; k+) tNode1 = tNode1.next; while (tNode1 != tNode2) tNode1 = tNode1.next; tNode2 = tNode2.next; /两个指针一样了,返回谁都一样。 return tNode1; else /长度相等会进此分支,只不过第一个循环不执行。其余,类似逻辑,只不过判断在外,这样代码多了,但是快一些。 for (int k = 0; k f; k+) tNode2 = tNode2.next; while (tNode1 != tNode2) tNode1 = tNod
7、e1.next; tNode2 = tNode2.next; return tNode1; 1-1-1-3链表倒数第N个节点给定一个单链表,头节点为node head.找出其倒数第N个节点。算法思路即为给定两个Node,起初在Head 节点向后走的时候,使另外一个节点node1托管这个链表的头,在Head向后走了N个节点后,node1向后遍历,在Head为Null时,node1即指向了倒数第N个节点。算法可以如下:public Node FindCountdownNode(Node head, int N) if (head = null) return null; /两个托管指针。 Node
8、 nTmpNode = head; Node nCountDownNode = head; /循环结束后,两个指针相差距离为N for (int i = 0; i N; i+) nTmpNode = nTmpNode.next; /走到结尾即可。 while (nTmpNode != null) nTmpNode = nTmpNode.next; nCountDownNode = nCountDownNode.next; return nCountDownNode; 1-1-1-4删除单个节点删除单链表中的某节点,或者不知道头节点,这时需要保证此节点不是最后一个节点,或者即使让你知道头节点,但
9、是不允许循环遍历。思路即为,因为知道这个节点,不遍历,能找到的只有他下一个节点以及他本身,这样的话将他下一个节点的数据和next属性付给当前节点,并将下一节点删除即可,偷梁换柱,达到效果。代码可以如下:public void DeleOndeNode(Node randomNode) /没有判断 Node myNext = randomNode.next; if (myNext != null) randomNode.data = myNext.data; randomNode.next = myNext.next; myNext = null; else /*只有当给定head时候才可以处理
10、末尾节点,代码为 Node curr_node = head; while(curr_node.next!=ramdomNode) curr_node= curr_node.next; curr_node = NULL; */ 1-1-1-5链表是否有环如何判断一个链表是否有环存在。思路为定义两个指针,即好像在操场上跑步,只要两个人速度不一样,速度快的肯定会有套速度慢的一圈的时刻。难点的还可以加上找到环的入口点,这里暂且不说。代码可以如下public bool IsExistLoop(Node Head) if (Head = null | Head.next = null) return f
11、alse; if (Head.next = Head) return true; Node slowH = Head; Node fastH = Head.next; /两个指针开始追逐 while (slowH != fastH & fastH != null & fastH.next != null) slowH = slowH.next; fastH = fastH.next.next; /退出循环的条件未知,判断一下是否有环 if (slowH = fastH) return true; return false; 1-1-1-6两个递增链表合并为递减链表给定两个递增的链表,头节点分别
12、为head1,head2,如何操作使之合并为一个递减的链表。思路为经典的二路归并排序算法,建立一个新链表,开始遍历两个链表,将数值小的插入到新链表的末尾,并且将该节点原来指针向前移动一次,继续比较,大多数情况在遍历玩一个链表后,另外一个会有剩余节点,需要处理。代码可以如下public void MergeSortList(Node head1, Node head2) /为了不破坏原有链表,依然设立托管指针。 Node Dele1 = head1; Node Dele2 = head2; Node tmpNode = null; Node tmpNode2 = null; Node head
13、= null; /判断链表的节点,谁的data值为小的,则将其对接在新链表的末尾,并将新链表前移一位。 /若两个链表值相等,则同时对接在末尾,并使dele1在前。 while (Dele1 != null & Dele2 != null) if (Dele1.data Dele2.data) tmpNode = Dele2.next; Dele12.next = head; head = Dele2; Dele2 = tmpNode; else tmpNode = Dele1.next; tmpNode2 = Dele2.next; Dele12.next = head; Dele1.next
14、 = Dele2; head = Dele1; Dele1 = tmpNode; Dele2 = tmpNode2; /在此循环之前,其中一个链表已经循环完毕了,下面就是看哪个链表还有剩余. /同逆转的思想,对接到新链表。 while (Dele1.next != null) tmpNode = Dele1.next; Dele1.next = head; head = Dele1; Dele1 = tmpNode; while (Dele2.next != null) tmpNode = Dele2.next; Dele2.next = head; head = Dele2; Dele2 =
15、 tmpNode; /此时head即为新链表的头节点,完成了降序排列,严格来说。 /此算法不是2路归并排序,二路归并排序具体效果是使两个升序链表生成新的升序链表。 /而在操作完了之后还需要一次逆转,我认为这样的效率不如直接逆转。 /如果采用传统的二路归并,核心代码应该如下,切记在完成之后需一次Reverse操作。 /* *判断谁小,假设dele1, *head.next = dele1 *head = dele1 *dele1 = dele1.next *等到循环完毕只需要用if不需要用while判断,对接到剩余的链表即可, *if(dele1!=null)head.next = dele1;
16、 *if(dele2!=null)head.next = dele2; */ 1-1-2二叉树在如下算法中所默认的二叉树节点结构均如下所示:public class BinTreeNode public object data; public BinTreeNode LeftChildTree; public BinTreeNode RightChildTree; 在对二叉树的操作中,频繁的会用到递归,分治的思想。同时由于二叉树的深度优先,广度优先遍历,以及先序,中序,后序的非递归方式涉及到堆栈以及队列,故列到后面,属于复合数据结构的部分。1-1-2-1先序,中序,后序遍历二叉树有3种遍历方式
17、,先序,中序,后序。三种遍历方式写法类似,都 用到了递归:遍历结果都知道,程序如下:public void PreOrder(BinTreeNode head) if (head != null) Console.WriteLine(head.data.ToString(); PreOrder(head.LeftChildTree); PreOrder(head.RightChildTree); public void MidOrder(BinTreeNode head) if (head != null) MidOrder(head.LeftChildTree); Console.Write
18、Line(head.data.ToString(); MidOrder(head.RightChildTree); public void PostOrder(BinTreeNode head) if (head != null) MidOrder(head.LeftChildTree); MidOrder(head.RightChildTree); Console.WriteLine(head.data.ToString(); 1-1-2-2求二叉树的深度同样用递归,算法如下public int GetDepth(BinTreeNode head) if (head = null) retu
19、rn 0; int leftDepth, rightDepth,totalDepth; leftDepth = GetDepth(head.LeftChildTree); rightDepth = GetDepth(head.RightChildTree); totalDepth = leftDepth rightDepth ? leftDepth + 1 : rightDepth + 1; return totalDepth; 1-1-2-3求二叉(排序)树的最近公共祖先算法思想,对于二叉排序树(binary search tree)有一个特点,就是对于一个root左节点都是小于他的valu
20、e的node节点,而root的右节点都大于root的value值,这样的话可以归纳出如下思考方法:当待寻找的两个节点node1和node2 ,满足node1.dataroot.data & node2.data head.data & node2.data head.data) return SearchCommonFather(node1, node2, head.RightChildTree); else if (node1.data head.data & node2.data head.LeftChildTree.nMaxRight ? nTempMax = head.LeftChildTree.nMaxLeft : nTempMax = head.LeftChildTree.nMaxRight; /将左右子树更深的+和根节点的这条连线,作为这个子树的深度。 head.LeftChildTree.nMaxLeft = nTempMax + 1; /右子树 if(head.RightChildTree != null) int nTempMax = 0; /判断左右子树哪个更深 head.RightChildTree.nMaxLeft head.RightChild
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1