知识大全 算法大全-面试题-数据结构(收录)
Posted 元素
篇首语:我自横刀向天笑,去留肝胆两昆仑。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 算法大全-面试题-数据结构(收录)相关的知识,希望对你有一定的参考价值。
一 单链表
目录
单链表反转
找出单链表的倒数第 个元素
找出单链表的中间元素
删除无头单链表的一个节点
两个不交叉的有序链表的合并
有个二级单链表 其中每个元素都含有一个指向一个单链表的指针 写程序把这个二级链表称一级单链表
单链表交换任意两个元素(不包括表头)
判断单链表是否有环?如何找到环的&# ;起始&# ;点?如何知道环的长度?
判断两个单链表是否相交
两个单链表相交 计算相交点
用链表模拟大整数加法运算
单链表排序
删除单链表中重复的元素
?
?
首先写一个单链表的C#实现 这是我们的基石
public class Link
public Link Next;
public string Data;
public Link(Link next string data)
this Next = next;
this Data = data;
?
?
其中 我们需要人为地在单链表前面加一个空节点 称其为head 例如 一个单链表是 > > 如图所示
?
?
?
对一个单链表的遍历如下所示
static void Main(string[] args)
Link head = GenerateLink();
Link curr = head;
while (curr != null)
Console WriteLine(curr Data);
curr = curr Next;
?
?
单链表反转
这道题目有两种算法 既然是要反转 那么肯定是要破坏原有的数据结构的
算法 我们需要额外的两个变量来存储当前节点curr的下一个节点next 再下一个节点nextnext
public static Link ReverseLink (Link head)
Link curr = head Next;
Link next = null;
Link nextnext = null;
//if no elements or only one element exists
if (curr == null || curr Next == null)
return head;
//if more than one element
while (curr Next != null)
next = curr Next; //
nextnext = next Next; //
next Next = head Next; //
head Next = next; //
curr Next = nextnext; //
return head;
?
?
算法的核心是while循环中的 句话
?
?
我们发现 curr始终指向第 个元素
此外 出于编程的严谨性 还要考虑 种极特殊的情况 没有元素的单链表 以及只有一个元素的单链表 都是不需要反转的
?
?
算法 自然是递归
如果题目简化为逆序输出这个单链表 那么递归是很简单的 在递归函数之后输出当前元素 这样能确保输出第N个元素语句永远在第N+ 个递归函数之后执行 也就是说第N个元素永远在第N+ 个元素之后输出 最终我们先输出最后一个元素 然后是倒数第 个 倒数第 个 直到输出第 个
public static void ReverseLink (Link head)
if (head Next != null)
ReverseLink (head Next);
Console WriteLine(head Next Data);
?
?
但是 现实应用中往往不是要求我们逆序输出(不损坏原有的单链表) 而是把这个单链表逆序(破坏型) 这就要求我们在递归的时候 还要处理递归后的逻辑
首先 要把判断单链表有 或 个元素这部分逻辑独立出来 而不需要在递归中每次都比较一次
public static Link ReverseLink (Link head)
//if no elements or only one element exists
if (head Next == null || head Next Next == null)
return head;
head Next = ReverseLink(head Next);
return head;
?
?
我们观测到
head Next = ReverseLink(head Next);
这句话的意思是为ReverseLink方法生成的逆序链表添加一个空表头
接下来就是递归的核心算法ReverseLink了
static Link ReverseLink(Link head)
if (head Next == null)
return head;
Link rHead = ReverseLink(head Next);
head Next Next = head;
head Next = null;
return rHead;
?
?
算法的关键就在于递归后的两条语句
head Next Next = head; //
head Next = null; //
啥意思呢?画个图表示就是
?
?
这样 就得到了一个逆序的单链表 我们只用到了 个额外的变量rHead
?
?
找出单链表的倒数第 个元素
这道题目有两种算法 但无论哪种算法 都要考虑单链表少于 个元素的情况
第 种算法 建立两个指针 第一个先走 步 然后第 个指针也开始走 两个指针步伐(前进速度)一致
static Link GetLast thOne(Link head)
Link first = head;
Link second = head;
for (int i = ; i < ; i++)
if (first Next == null)
throw new Exception(&# ;Less than elements&# ;);
first = first Next;
while (first != null)
first = first Next;
second = second Next;
return second;
?
?
第 种算法 做一个数组arr[ ] 让我们遍历单链表 把第 个 第 个 第 个……第 N个扔到arr[ ] 把第 个 第 个 第 个……第 N+ 个扔到arr[ ] 把第 个 第 个 第 个……第 N+ 个扔到arr[ ] 把第 个 第 个 第 个……第 N+ 个扔到arr[ ] 这样随着单链表的遍历结束 arr中存储的就是单链表的最后 个元素 找到最后一个元素对应的arr[i] 让k=(i+ )% 则arr[k]就是倒数第 个元素
static Link GetLast thOneByArray(Link head)
Link curr = head;
int i = ;
Link[] arr = new Link[ ];
while (curr Next != null)
arr[i] = curr Next;
curr = curr Next;
i = (i + ) % ;
if (arr[i] == null)
throw new Exception(&# ;Less than elements&# ;);
return arr[i];
?
?
本题目源代码下载
推而广之 对倒数第K个元素 都能用以上 种算法找出来
?
?
找出单链表的中间元素
算法思想 类似于上题 还是使用两个指针first和second 只是first每次走一步 second每次走两步
static Link GetMiddleOne(Link head)
Link first = head;
Link second = head;
while (first != null && first Next != null)
first = first Next Next;
second = second Next;
return second;
但是 这道题目有个地方需要注意 就是对于链表元素个数为奇数 以上算法成立 如果链表元素个数为偶数 那么在返回second的同时 还要返回second Next也就是下一个元素 它俩都算是单链表的中间元素
下面是加强版的算法 无论奇数偶数 一概通杀
static void Main(string[] args)
Link head = GenerateLink();
bool isOdd = true;
Link middle = GetMiddleOne(head ref isOdd);
if (isOdd)
Console WriteLine(middle Data);
else
Console WriteLine(middle Data);
Console WriteLine(middle Next Data);
Console Read();
static Link GetMiddleOne(Link head ref bool isOdd)
Link first = head;
Link second = head;
while (first != null && first Next != null)
first = first Next Next;
second = second Next;
if (first != null)
isOdd = false;
return second;
?
?
一个单链表 很长 遍历一遍很慢 我们仅知道一个指向某节点的指针curr 而我们又想删除这个节点
这道题目是典型的&# ;狸猫换太子&# ; 如下图所示
?
?
如果不考虑任何特殊情况 代码就 行
curr Data = curr Next Data;
?
curr Next = curr Next Next;
上述代码由一个地方需要注意 就是如果要删除的是最后一个元素呢?那就只能从头遍历一次找到倒数第二个节点了
?
?
此外 这道题目的一个变身就是将一个环状单链表拆开(即删除其中一个元素) 此时 只要使用上面那两行代码就可以了 不需要考虑表尾
相关问题 只给定单链表中某个结点p(非空结点) 在p前面插入一个结点q
话说 交换单链表任意两个节点 也可以用交换值的方法 但这样就没意思了 所以 才会有第 题霸王硬上工的做法
?
?
两个不交叉的有序链表的合并
有两个有序链表 各自内部是有序的 但是两个链表之间是无序的
算法思路 当然是循环逐项比较两个链表了 如果一个到了头 就不比较了 直接加上去
注意 对于 个元素的Data相等(仅仅是Data相等哦 而不是相同的引用) 我们可以把它视作前面的Data大于后面的Data 从而节省了算法逻辑
static Link MergeTwoLink(Link head Link head )
Link head = new Link(null Int MinValue);
Link pre = head;
Link curr = head Next;
Link curr = head ;
Link curr = head ;
//pare until one link run to the end
while (curr Next != null && curr Next != null)
if (curr Next Data < curr Next Data)
curr = new Link(null curr Next Data);
curr = curr Next;
else
curr = new Link(null curr Next Data);
curr = curr Next;
pre Next = curr;
pre = pre Next;
//if head run to the end
while (curr Next != null)
curr = new Link(null curr Next Data);
curr = curr Next;
pre Next = curr;
pre = pre Next;
//if head run to the end
while (curr Next != null)
curr = new Link(null curr Next Data);
curr = curr Next;
pre Next = curr;
pre = pre Next;
return head;
?
?
如果这两个有序链表交叉组成了Y型呢 比如说
?
这时我们需要先找出这个交叉点(图中是 ) 这个算法参见第 题 我们这里直接使用第 道题目中的方法GetIntersect
然后局部修改上面的算法 只要其中一个链表到达了交叉点 就直接把另一个链表的剩余元素都加上去 如下所示
static Link MergeTwoLink (Link head Link head )
Link head = new Link(null Int MinValue);
Link pre = head;
Link curr = head Next;
Link intersect = GetIntersect(head head );
Link curr = head ;
Link curr = head ;
//pare until one link run to the intersect
while (curr Next != intersect && curr Next != intersect)
if (curr Next Data < curr Next Data)
curr = new Link(null curr Next Data);
curr = curr Next;
else
curr = new Link(null curr Next Data);
curr = curr Next;
pre Next = curr;
pre = pre Next;
//if head run to the intersect
if (curr Next == intersect)
while (curr Next != null)
curr = new Link(null curr Next Data);
curr = curr Next;
pre Next = curr;
pre = pre Next;
//if head run to the intersect
else if (curr Next == intersect)
while (curr Next != null)
curr = new Link(null curr Next Data);
curr = curr Next;
pre Next = curr;
pre = pre Next;
return head;
?
?
有个二级单链表 其中每个元素都含有一个指向一个单链表的指针 写程序把这个二级链表展开称一级单链表
这个简单 就是说 这个二级单链表只包括一些head
public class Link
public Link Next;
public int Data;
public Link(Link next int data)
this Next = next;
this Data = data;
public class CascadeLink
public Link Next;
public CascadeLink NextHead;
public CascadeLink(CascadeLink nextHead Link next)
this Next = next;
this NextHead = nextHead;
?
?
下面做一个二级单链表 GenerateLink 和GenerateLink 方法在前面都已经介绍过了
public static CascadeLink GenerateCascadeLink()
Link head = GenerateLink ();
Link head = GenerateLink ();
Link head = GenerateLink ();
CascadeLink element = new CascadeLink(null head );
CascadeLink element = new CascadeLink(element head );
CascadeLink element = new CascadeLink(element head );
CascadeLink head = new CascadeLink(element null);
return head;
就是说 这些单链表的表头head head head head …… 它们组成了一个二级单链表head null –> head –> head –> head –> head
–>
?
?
我们的算法思想是 进行两次遍历 在外层用curr 遍历二级单链表head 在内层用curr 遍历每个单链表
public static Link GenerateNewLink(CascadeLink head)
CascadeLink curr = head NextHead;
Link newHead = curr Next;
Link curr = newHead;
while (curr != null)
curr Next = curr Next Next;
while (curr Next != null)
curr = curr Next;
curr = curr NextHead;
return newHead;
?
?
其中 curr Next = curr Next Next; 这句话是关键 它负责把上一个单链表的表尾和下一个单链表的非空表头连接起来
?
?
单链表交换任意两个元素(不包括表头)
先一次遍历找到这两个元素curr 和curr 同时存储这两个元素的前驱元素pre 和pre
然后大换血
public static Link SwitchPoints(Link head Link p Link q)
if (p == head || q == head)
throw new Exception(&# ;No exchange with head&# ;);
if (p == q)
return head;
//find p and q in the link
Link curr = head;
Link curr = p;
Link curr = q;
Link pre = null;
Link pre = null;
?
int count = ;
while (curr != null)
if (curr Next == p)
pre = curr;
count++;
if (count == )
break;
else if (curr Next == q)
pre = curr;
count++;
if (count == )
break;
curr = curr Next;
curr = curr Next;
pre Next = curr ;
curr Next = curr Next;
pre Next = curr ;
curr Next = curr;
return head;
注意特例 如果相同元素 就没有必要交换 如果有一个是表头 就不交换
?
?
判断单链表是否有环?如何找到环的&# ;起始&# ;点?如何知道环的长度?
算法思想
先分析是否有环 为此我们建立两个指针 从header一起向前跑 一个步长为 一个步长为 用while(直到步长 的跑到结尾)检查两个指针是否相等 直到找到为止
static bool JudgeCircleExists(Link head)
Link first = head; // step each time
Link second = head; // steps each time
while (second Next != null && second Next Next != null)
second = second Next Next;
first = first Next;
if (second == first)
return true;
return false;
?
?
那又如何知道环的长度呢?
根据上面的算法 在返回true的地方 也就是 个指针相遇处 这个位置的节点P肯定位于环上 我们从这个节点开始先前走 转了一圈肯定能回来
static int GetCircleLength(Link point)
int length = ;
Link curr = point;
while (curr Next != point)
length++;
curr = curr Next;
return length;
?
?
继续我们的讨论 如何找到环的&# ;起始&# ;点呢?
延续上面的思路 我们仍然在返回true的地方P 计算一下从有环单链表的表头head到P点的距离
static int GetLengthFromHeadToPoint(Link head Link point)
int length = ;
Link curr = head;
while (curr != point)
length++;
curr = curr Next;
return length;
?
?
如果我们把环从P点&# ;切开&# ;(当然并不是真的切 那就破坏原来的数据结构了) 那么问题就转化为计算两个相交&# ;单链表&# ;的交点(第 题)
一个单链表是从P点出发 到达P(一个回圈) 距离M 另一个单链表从有环单链表的表头head出发 到达P 距离N
我们可以参考第 题的GetIntersect方法并稍作修改
private static Link FindIntersect(Link head)
Link p = null;
//get the point in the circle
bool result = JudgeCircleExists(head ref p);
if (!result) return null;
Link curr = head Next;
Link curr = p Next;
//length from head to p
int M = ;
while (curr != p)
M++;
curr = curr Next;
//circle length
int N = ;
while (curr != p)
N++;
curr = curr Next;
//recover curr & curr
curr = head Next;
curr = p Next;
//make links have the same distance to the intersect
if (M > N)
for (int i = ; i < M &# ; N; i++)
curr = curr Next;
else if (M < N)
for (int i = ; i < N &# ; M; i++)
curr = curr Next;
//goto the intersect
while (curr != p)
if (curr == curr )
return curr ;
curr = curr Next;
curr = curr Next;
return null;
?
?
判断两个单链表是否相交
这道题有多种算法
算法 把第一个链表逐项存在hashtable中 遍历第 个链表的每一项 如果能在第一个链表中找到 则必然相交
static bool JudgeIntersectLink (Link head Link head )
Hashtable ht = new Hashtable();
Link curr = head ;
Link curr = head ;
//store all the elements of link
while (curr Next != null)
ht[curr Next] = string Empty;
curr = curr Next;
//check all the elements in link if exists in Hashtable or not
while (curr Next != null)
//if exists
if (ht[curr Next] != null)
return true;
curr = curr Next;
return false;
?
?
算法 把一个链表A接在另一个链表B的末尾 如果有环 则必然相交 如何判断有环呢?从A开始遍历 如果能回到A的表头 则肯定有环
注意 在返回结果之前 要把刚才连接上的两个链表断开 恢复原状
static bool JudgeIntersectLink (Link head Link head )
bool exists = false;
Link curr = head ;
Link curr = head ;
?
//goto the end of the link
while (curr Next != null)
curr = curr Next;
//join these o links
curr Next = head ;
//iterate link
while (curr Next != null)
if (curr Next == head )
exists = true;
break;
curr = curr Next;
//recover original status whether exists or not
curr Next = null;
return exists;
?
?
算法 如果两个链表的末尾元素相同 则必相交
static bool JudgeIntersectLink (Link head Link head )
Link curr = head ;
Link curr = head ;
//goto the end of the link
while (curr Next != null)
curr = curr Next;
//goto the end of the link
while (curr Next != null)
curr = curr Next;
if (curr != curr )
return false;
else
return true;
?
两个单链表相交 计算相交点
分别遍历两个单链表 计算出它们的长度M和N 假设M比N大 则长度M的链表先前进M N 然后两个链表同时以步长 前进 前进的同时比较当前的元素 如果相同 则必是交点
public static Link GetIntersect(Link head Link head )
Link curr = head ;
Link curr = head ;
int M = N = ;
//goto the end of the link
while (curr Next != null)
curr = curr Next;
M++;
//goto the end of the link
while (curr Next != null)
curr = curr Next;
N++;
//return to the begining of the link
curr = head ;
curr = head ;
if (M > N)
for (int i = ; i < M &# ; N; i++)
curr = curr Next;
else if (M < N)
for (int i = ; i < N &# ; M; i++)
curr = curr Next;
while (curr Next != null)
if (curr == curr )
return curr ;
curr = curr Next;
curr = curr Next;
return null;
?
?
用链表模拟大整数加法运算
例如 > > >NULL + >NULL =>
> > > >NULL
肯定是使用递归啦 不然没办法解决进位+ 问题 因为这时候要让前面的节点加 而我们的单链表是永远指向前的
此外对于 + = 新得到的值的位数( 位)比原来的两个值( 个 位 个 位)都多 所以我们将表头的值设置为 如果多出一位来 就暂时存放到表头 递归结束后 如果表头为 就在新的链表外再加一个新的表头
//head length > head so M > N
public static int Add(Link head Link head ref Link newHead int M int N)
// goto the end
if (head == null)
return ;
int temp = ;
int result = ;
newHead = new Link(null );
if (M > N)
result = Add(head Next head ref newHead Next M &# ; N);
temp = head Data + result;
newHead Data = temp % ;
return temp >=
: ;
else // M == N
result = Add(head Next head Next ref newHead Next M &# ; N &# ; );
temp = head Data + head Data + +result;
newHead Data = temp % ;
return temp >=
: ;
这里假设head 比head 长 而且M N分别是head 和head 的长度
?
?
单链表排序
无外乎是冒泡 选择 插入等排序方法 关键是交换算法 需要额外考虑 第 题我编写了一个交换算法 在本题的排序过程中 我们可以在外层和内层循环里面 捕捉到pre 和pre 然后进行交换 而无需每次交换又要遍历一次单链表
在实践中 我发现冒泡排序和选择排序都要求内层循环从链表的末尾向前走 这明显是不合时宜的
所以我最终选择了插入排序算法 如下所示
先给出基于数组的算法
?
?
代码
static int[]
InsertSort(int[] arr)
for(int i= ; i<arr Length;i++)
for(int j =i; (j> )&&arr[j]<arr[j ];j&# ;)
arr[j]=arr[j]^arr[j ];
arr[j ]=arr[j]^arr[j ];
arr[j]=arr[j]^arr[j ];
?
return arr;
仿照上面的思想 我们来编写基于Link的算法
public static Link SortLink(Link head)
Link pre = head;
Link pre = head Next;
Link min = null;
for (Link curr = head Next; curr != null; curr = min Next)
if (curr Next == null)
break;
min = curr ;
for (Link curr = curr Next; curr != null; curr = curr Next)
//swap curr and curr
if (curr Data < curr Data)
min = curr ;
curr = curr ;
curr = min;
pre Next = curr ;
curr Next = curr Next;
curr Next = pre ;
//if exchange element n and n no need to add reference from pre to curr because they are the same one
if (pre != curr )
pre Next = curr ;
pre = curr ;
pre = min;
pre = min Next;
return head;
?
?
值得注意的是 很多人的算法不能交换相邻两个元素 这是因为pre 和curr 是相等的 如果此时还执行pre Next = curr ; 会造成一个自己引用自己的环
?
?
交换指针很是麻烦 而且效率也不高 需要经常排序的东西最好不要用链表来实现 还是数组好一些
?
?
删除单链表中重复的元素
用Hashtable辅助 遍历一遍单链表就能搞定
实践中发现 curr从表头开始 每次判断下一个元素curr Netx是否重复 如果重复直接使用curr Next = curr Next Next; 就可以删除重复元素——这是最好的算法 唯一的例外就是表尾 所以到达表尾 就break跳出while循环
public static Link DeleteDuplexElements(Link head)
Hashtable ht = new Hashtable();
Link curr = head;
while (curr != null)
if (curr Next == null)
break;
if (ht[curr Next Data] != null)
curr Next = curr Next Next;
else
ht[curr Next Data] = &# ;&# ;;
curr = curr Next;
return head;
?
?
?
?
结语
单链表只有一个向前指针Next 所以要使用 个额外变量来存储当前元素的前一个或后一个指针
尽量用while循环而不要用for循环 来进行遍历
哇塞 我就是不用指针 照样能&# ;修改地址&# ; 达到和C++同样的效果 虽然很烦~
遍历的时候 不要在while循环中head=head Next;这样会改变原先的数据结构 我们要这么写 Link curr=head;然后curr=curr Next;
有时我们需要临时把环切开 有时我们需要临时把单链表首尾相连成一个环
究竟是玩curr还是curr Next 根据不同题目而各有用武之地 没有定论 不必强求
?
?
二 栈和队列
?
目录
设计含min函数的栈 要求min push和pop的时间复杂度都是o( )
设计含min函数的栈的另解
用两个栈实现队列
用两个队列实现栈
?
栈的push pop序列是否一致
递归反转一个栈 要求不得重新申请一个同样的栈 空间复杂度o( )
给栈排个序
如何用一个数组实现两个栈
如何用一个数组实现三个栈
?
?
设计含min函数的栈 要求min push和pop的时间复杂度都是o( )
算法思想 需要设计一个辅助栈 用来存储当前栈中元素的最小值 网上有人说存储当前栈中元素的最小值的所在位置 虽然能节省空间 这其实是不对的 因为我在调用Min函数的时候 只能得到位置 还要对存储元素的栈不断的pop 才能得到最小值——时间复杂度o( )
所以 还是在辅助栈中存储元素吧
此外 还要额外注意Push操作 第一个元素不用比较 自动成为最小值入栈 其它元素每次都要和栈顶元素比较 小的那个放到栈顶
?
public class NewStack
private Stack dataStack;
private Stack mindataStack;
public NewStack()
dataStack = new Stack();
mindataStack = new Stack();
public void Push(int element)
dataStack Push(element);
if (mindataStack Count == )
mindataStack Push(element);
else if (element <= (int)mindataStack Peek())
mindataStack Push(element);
else //(element > mindataStack Peek)
mindataStack Push(mindataStack Peek());
?
public int Pop()
if (dataStack Count == )
throw new Exception(&# ;The stack is empty&# ;);
?
mindataStack Pop();
return (int)dataStack Pop();
public int Min()
if (dataStack Count == )
throw new Exception(&# ;The stack is empty&# ;);
?
return (int)mindataStack Peek();
?
?
?
设计含min函数的栈的另解
话说 和青菜脸呆久了 就沾染了上海小市民意识 再加上原本我就很抠门儿 于是对于上一题目 我把一个栈当成两个用 就是说 每次push 先入站当前元素 然后入栈当前栈中最小元素 pop则每次弹出 个元素
算法代码如下所示(这里最小元素位于当前元素之上 为了下次比较方便)
public class NewStack
private Stack stack;
public NewStack()
stack = new Stack();
public void Push(int element)
if (stack Count == )
stack Push(element);
stack Push(element);
else if (element <= (int)stack Peek())
stack Push(element);
stack Push(element);
else //(element > stack Peek)
object min = stack Peek();
stack Push(element);
stack Push(min);
public int Pop()
if (stack Count == )
throw new Exception(&# ;The stack is empty&# ;);
stack Pop();
return (int)stack Pop();
public int Min()
if (stack Count == )
throw new Exception(&# ;The stack is empty&# ;);
return (int)stack Peek();
?
?
之所以说我这个算法比较叩门 是因为我只使用了一个栈 空间复杂度o(N) 节省了一半的空间(算法 的空间复杂度o( N))
?
?
?
?
用两个栈实现队列
实现队列 就要实现它的 个方法 Enqueue(入队) Dequeue(出队)和Peek(队头)
)stack 存的是每次进来的元素 所以Enqueue就是把进来的元素push到stack 中
)而对于Dequeue 一开始stack 是空的 所以我们把stack 中的元素全都pop到stack 中 这样stack 的栈顶就是队头 只要stack 不为空 那么每次出队 就相当于stack 的pop
)接下来 每入队一个元素 仍然push到stack 中 每出队一个元素 如果stack 不为空 就从stack 中pop一个元素 如果stack 为空 就重复上面的操作——把stack 中的元素全都pop到stack 中
)Peek操作 类似于Dequeue 只是不需要出队 所以我们调用stack 的Peek操作 当然 如果stack 为空 就把stack 中的元素全都pop到stack 中
)注意边界的处理 如果stack 和stack 都为空 才等于队列为空 此时不能进行Peek和Dequeue操作
按照上述分析 算法实现如下
public class NewQueue
private Stack stack ;
private Stack stack ;
public NewQueue()
stack = new Stack();
stack = new Stack();
public void Enqueue(int element)
stack Push(element);
public int Dequeue()
if (stack Count == )
if (stack Count == )
throw new Exception(&# ;The queue is empty&# ;);
else
while (stack Count > )
stack Push(stack Pop());
return (int)stack Pop();
public int Peek()
if (stack Count == )
if (stack Count == )
throw new Exception(&# ;The queue is empty&# ;);
else
while (stack Count > )
stack Push(stack Pop());
return (int)stack Peek();
?
?
?
用两个队列实现栈
这个嘛 就要queue 和queue 轮流存储数据了 这个&# ;轮流&# ;发生在Pop和Peek的时候 假设此时我们把所有数据存在queue 中(此时queue 为空) 我们把queue 的n 个元素放到queue 中 queue中最后一个元素就是我们想要pop的元素 此时queue 存有n 个元素(queue 为空)
至于Peek 则是每次转移n个数据 再转移最后一个元素的时候 将其计下并返回
那么Push的操作 则需要判断当前queue 和queue 哪个为空 将新元素放到不为空的队列中
public class NewStack
private Queue queue ;
private Queue queue ;
public NewStack()
queue = new Queue();
queue = new Queue();
public void Push(int element)
if (queue Count == )
queue Enqueue(element);
else
queue Enqueue(element);
public int Pop()
if (queue Count == && queue Count == )
throw new Exception(&# ;The stack is empty&# ;);
if (queue Count > )
while (queue Count > )
queue Enqueue(queue Dequeue());
//还剩一个
return (int)queue Dequeue();
else //queue Count >
while (queue Count > )
queue Enqueue(queue Dequeue());
//还剩一个
return (int)queue Dequeue();
public int Peek()
if (queue Count == && queue Count == )
throw new Exception(&# ;The stack is empty&# ;);
int result = ;
if (queue Count > )
while (queue Count > )
queue Enqueue(queue Dequeue());
//还剩一个
result = (int)queue Dequeue();
queue Enqueue(result);
else //queue Count >
while (queue Count > )
queue Enqueue(queue Dequeue());
//还剩一个
result = (int)queue Dequeue();
queue Enqueue(result);
return result;
?
?
?
栈的push pop序列是否一致
输入两个整数序列 其中一个序列表示栈的push顺序 判断另一个序列有没有可能是对应的pop顺序 为了简单起见 我们假设push序列的任意两个整数都是不相等的
比如输入的push序列是 那么 就有可能是一个pop系列 因为可以有如下的push和pop序列 push push push push pop push pop pop pop pop 这样得到的pop序列就是 但序列 就不可能是push序列 的pop序列
?
?
网上的若干算法都太复杂了 现提出包氏算法如下
先for循环把arr 中的元素入栈 并在每次遍历时 检索arr 中可以pop的元素 如果循环结束 而stack中还有元素 就说明arr 序列不是pop序列
static bool
JudgeSequenceIsPossible(int[] arr int[] arr )
Stack stack = new Stack();
for (int i = j = ; i < arr Length; i++)
stack Push(arr [i]);
while(stack Count > && (int)stack Peek() == arr [j])
stack Pop();
j++;
return stack Count == ;
?
?
?
?
递归反转一个栈 要求不得重新申请一个同样的栈 空间复杂度o( )
算法思想 汉诺塔的思想 非常复杂 玩过九连环的人都想得通的
static void ReverseStack(ref Stack stack)
if (stack Count == )
return;
object top = stack Pop();
ReverseStack(ref stack);
if (stack Count == )
stack Push(top);
return;
object top = stack Pop();
ReverseStack(ref stack);
stack Push(top);
ReverseStack(ref stack);
stack Push(top );
?
?
给栈排个序
本题目是上一题目的延伸
static void Sort(ref Stack stack)
if (stack Count == )
return;
object top = stack Pop();
Sort(ref stack);
if (stack Count == )
stack Push(top);
return;
object top = stack Pop();
if ((int)top > (int)top )
stack Push(top);
Sort(ref stack);
stack Push(top );
else
stack Push(top );
Sort(ref stack);
stack Push(top);
?
?
?
?
如何用一个数组实现两个栈
继续我所提倡的抠门儿思想 也不枉我和青菜脸相交一场
网上流传着两种方法
方法
采用交叉索引的方法
一号栈所占数组索引为 &# ;&# ;(K* )
?
?
?
二号栈所占数组索引为 &# ;&# ;(K* + )
?
算法实现如下
public class NewStack
object[] arr;
int top ;
int top ;
public NewStack(int capticy)
arr = new object[capticy];
top = ;
top = ;
public void Push(int type object element)
if (type == )
if (top + >= arr Length)
throw new Exception(&# ;The stack is full&# ;);
else
top += ;
arr[top ] = element;
else //type==
if (top + >= arr Length)
throw new Exception(&# ;The stack is full&# ;);
else
top += ;
arr[top ] = element;
public object Pop(int type)
object obj = null;
if (type == )
if (top == )
throw new Exception(&# ;The stack is empty&# ;);
else
obj = arr[top ];
arr[top ] = null;
top = ;
else //type ==
if (top == )
throw new Exception(&# ;The stack is empty&# ;);
else
obj = arr[top ];
arr[top ] = null;
top = ;
return obj;
public object Peek(int type)
if (type == )
if (top == )
throw new Exception(&# ;The stack is empty&# ;);
return arr[top ];
else //type ==
if (top == )
throw new Exception(&# ;The stack is empty&# ;);
return arr[top ];
?
?
?
方法
第一个栈A 从最左向右增长
?
第二个栈B 从最右向左增长
?
代码实现如下
public class NewStack
object[] arr;
int top ;
int top ;
public NewStack(int capticy)
arr = new object[capticy];
top = ;
top = capticy;
public void Push(int type object element)
if (top == top )
throw new Exception(&# ;The stack is full&# ;);
if (type == )
arr[top ] = element;
top ++;
else //type==
top &# ;;
arr[top ] = element;
public object Pop(int type)
object obj = null;
if (type == )
if (top == )
throw new Exception(&# ;The stack is empty&# ;);
else
top &# ;;
obj = arr[top ];
arr[top ] = null;
else //type ==
if (top == arr Length)
throw new Exception(&# ;The stack is empty&# ;);
else
obj = arr[top ];
arr[top ] = null;
top ++;
return obj;
public object Peek(int type)
if (type == )
if (top == )
throw new Exception(&# ;The stack is empty&# ;);
return arr[top ];
else //type ==
if (top == arr Length)
throw new Exception(&# ;The stack is empty&# ;);
return arr[top ];
综合比较上述两种算法 我们发现 算法 实现的两个栈 每个都只有n/ 个空间大小 而算法 实现的两个栈 如果其中一个很小 另一个则可以很大 它们的和为常数n
?
?
如何用一个数组实现三个栈
最后 让我们把抠门儿进行到底 相信看完本文 你已经从物质和精神上都升级为一个抠门儿主义者
如果还使用交叉索引的办法 每个栈都只有N/ 个空间
让我们只好使用上个题目的第 个方法 不过这只能容纳 个栈 我们还需要一个位置存放第 个栈 不如考虑数组中间的位置——第 个栈的增长规律可以如下
第 个入栈C的元素进mid处
?
第 个入栈C的元素进mid+ 处
?
第 个入栈C的元素进mid 处
?
第 个入栈C的元素进mid+ 处
这个方法的好处是 每个栈都有接近N/ 个空间
public class NewStack
object[] arr;
int top ;
int top ;
int top _left;
int top _right;
bool isLeft;
public NewStack(int capticy)
arr = new object[capticy];
top = ;
top = capticy;
isLeft = true;
top _left = capticy / ;
top _right = top _left + ;
public void Push(int type object element)
if (type == )
if (top == top _left + )
throw new Exception(&# ;The stack is full&# ;);
arr[top ] = element;
top ++;
else if (type == )
if (top == top _right)
throw new Exception(&# ;The stack is full&# ;);
top &# ;;
arr[top ] = element;
else //type==
if (isLeft)
if (top == top _left + )
throw new Exception(&# ;The stack is full&# ;);
arr[top _left] = element;
top _left&# ;;
else
if (top == top _right)
throw new Exception(&# ;The stack is full&# ;);
arr[top _right] = element;
top _right++;
isLeft = !isLeft;
public object Pop(int type)
object obj = null;
if (type == )
if (top == )
throw new Exception(&# ;The stack is empty&# ;);
else
top &# ;;
obj = arr[top ];
arr[top ] = null;
else if (type == )
if (top == arr Length)
throw new Exception(&# ;The stack is empty&# ;);
else
obj = arr[top ];
arr[top ] = null;
top ++;
else //type==
if (top _right == top _left + )
throw new Exception(&# ;The stack is empty&# ;);
if (isLeft)
top _left++;
obj = arr[top _left];
arr[top _left] = null;
else
top _right&# ;;
obj = arr[top _right];
arr[top _right] = null;
isLeft = !isLeft;
return obj;
public object Peek(int type)
if (type == )
if (top == )
throw new Exception(&# ;The stack is empty&# ;);
return arr[top ];
else if (type == )
if (top == arr Length)
throw new Exception(&# ;The stack is empty&# ;);
return arr[top ];
else //type==
if (top _right == top _left + )
throw new Exception(&# ;The stack is empty&# ;);
if (isLeft)
return arr[top _left + ];
else
return arr[top _right ];
?
?
?
?
三 二叉树
目录
二叉树三种周游(traversal)方式
怎样从顶部开始逐层打印二叉树结点数据
如何判断一棵二叉树是否是平衡二叉树
设计一个算法 找出二叉树上任意两个节点的最近共同父结点 复杂度如果是O(n )则不得分
如何不用递归实现二叉树的前序/后序/中序遍历?
在二叉树中找出和为某一值的所有路径
怎样编写一个程序 把一个有序整数数组放到二叉树中?
判断整数序列是不是二叉搜索树的后序遍历结果
求二叉树的镜像
一棵排序二叉树(即二叉搜索树BST) 令 f=(最大值+最小值)/ 设计一个算法 找出距离f值最近 大于f值的结点 复杂度如果是O(n )则不得分
把二叉搜索树转变成排序的双向链表
?
?
?
?
?
?
首先写一个二叉树的C#实现 这是我们的基石
public class BinNode
public int Element;
public BinNode Left;
public BinNode Right;
public BinNode(int element BinNode left BinNode right)
this Element = element;
this Left = left;
this Right = right;
?
public bool IsLeaf()
return this Left == null && this Right == null;
?
?
二叉树三种周游(traversal)方式
)前序周游(preorder) 节点 –> 子节点Left(包括其子树) –> 子节点Right(包括其子树)
static void PreOrder(BinNode root)
if (root == null)
return;
//visit current node
Console WriteLine(root Element);
PreOrder(root Left);
PreOrder(root Right);
?
?
)后序周游(postorder) 子节点Left(包括其子树) –> 子节点Right(包括其子树) –> 节点
static void PostOrder(BinNode root)
if (root == null)
return;
PostOrder(root Left);
PostOrder(root Right);
//visit current node
Console WriteLine(root Element);
?
?
)中序周游(inorder) 子节点Left(包括其子树) –> 节点 –> 子节点Right(包括其子树)
static void InOrder(BinNode root)
if (root == null)
return;
InOrder(root Left);
//visit current node
Console WriteLine(root Element);
InOrder(root Right);
?
?
我们发现 三种周游的code实现 仅仅是访问当前节点的这条语句所在位置不同而已
?
?
怎样从顶部开始逐层打印二叉树结点数据
有 种算法
算法 基于Queue来实现 也就是广度优先搜索(BFS)的思想
static void PrintTree (BinNode root)
if (root == null) return;
BinNode tmp = null;
Queue queue = new Queue();
queue Enqueue(root);
while (queue Count > )
tmp = (BinNode)queue Dequeue();
Console WriteLine(tmp Element);
if (tmp Left != null)
queue Enqueue(tmp Left);
if (tmp Right != null)
queue Enqueue(tmp Right);
?
?
话说 BFS和DFS思想本来是用于图的 但我们不能被传统的思维方式所束缚
?
?
算法 基于单链表实现
如果没有Queue给我们用 我们只好使用单链表 把每个节点存在单链表的Data中 实现如下
public class Link
public Link Next;
public BinNode Data;
public Link(Link next BinNode data)
this Next = next;
this Data = data;
看过了Queue的实现 我们发现永远是先出队 个(队头) 然后入队 个(把出队的Left和Right放到队尾)
对于单链表而言 我们可以先模拟入队——把first的Data所对应的Left和Right 先后插到second的后面 即second Next和second Next Next位置 同时second向前走 或 次 再次到达链表末尾 这取决于Left和Right是否为空 然后我们模拟出队——first前进 步
当first指针走不下去了 那么任务也就结束了
static void PrintTree (BinNode root)
if (root == null) return;
Link head = new Link(null root);
Link first = head;
Link second = head;
while (first != null)
if (first Data Left != null)
second Next = new Link(null first Data Left);
second = second Next;
if (first Data Right != null)
second Next = new Link(null first Data Right);
second = second Next;
Console WriteLine(first Data Element);
first = first Next;
?
?
如何判断一棵二叉树是否是平衡二叉树
平衡二叉树的定义 如果任意节点的左右子树的深度相差不超过 那这棵树就是平衡二叉树
算法思路 先编写一个计算二叉树深度的函数GetDepth 利用递归实现 然后再递归判断每个节点的左右子树的深度是否相差
static int GetDepth(BinNode root)
if (root == null)
return ;
int leftLength = GetDepth(root Left);
int rightLength = GetDepth(root Right);
return (leftLength > rightLength
leftLength : rightLength) + ;
?
?
注意这里的+ 对应于root不为空(算作当前 个深度)
static bool IsBalanceTree(BinNode root)
if (root == null)
return true;
int leftLength = GetDepth(root Left);
int rightLength = GetDepth(root Right);
int distance = leftLength > rightLength
leftLength &# ; rightLength : rightLength &# ; leftLength;
?
if (distance > )
return false;
else
return IsBalanceTree(root Left) && IsBalanceTree(root Right);
?
?
上述程序的逻辑是 只要当前节点root的Left和Right深度差不超过 就递归判断Left和Right是否也符合条件 直到为Left或Right为null 这意味着它们的深度为 能走到这一步 前面必然都符合条件 所以整个二叉树都符合条件
?
?
设计一个算法 找出二叉树上任意两个节点的最近共同父结点 复杂度如果是O(n)则不得分
本题网上有很多算法 都不怎么样 这里提出包氏的两个算法
算法 做一个容器 我们在遍历二叉树寻找节点的同时 把从根到节点的路径扔进去(两个节点就是两个容器) 由于根节点最后一个被扔进去 但我们接下来又需要第一个就能访问到它——后进先出 所以这个容器是一个栈 时间复杂度O(N) 空间复杂度O(N)
static bool GetPositionByNode(BinNode root BinNode node ref Stack stack)
if (root == null)
return false;
if (root == node)
stack Push(root);
return true;
if (GetPositionByNode(root Left node ref stack) || GetPositionByNode(root Right node ref stack))
stack Push(root);
return true;
return false;
?
?
然后我们要同时弹出这两个容器的元素 直到它们不相等 那么之前那个相等的元素就是我们要求的父亲节点
static BinNode FindParentNode(BinNode root BinNode node BinNode node )
Stack stack = new Stack();
GetPositionByNode(root node ref stack );
Stack stack = new Stack();
GetPositionByNode(root node ref stack );
BinNode tempNode = null;
while (stack Peek() == stack Peek())
tempNode = (BinNode)stack Pop();
stack Pop();
return tempNode;
?
?
算法 如果要求o( )的空间复杂度 就是说 只能用一个变量来辅助我们
我们选择一个 位的整数 然后从 开始 从左到右逐层为二叉树的每个元素赋值 root对应 root Left对应 root Right对应 依次类推 而不管实际这个位置上是否有节点 我们发现两个规律
////
////
////
////
如果要找的是 和 位置上的节点
我们发现 它们的二进制分别是 和 右移 使之与 位数相同 于是 变成了 (也就是 的父亲 )
这时 和 (也就是 和 位于同样的深度) 我们从左往右找 和 具有 位相同 即 这就是我们要找的 和 的父亲 也就是 和 的最近父亲
由上面观察 得到算法
)将找到的两个节点对应的数字
static bool GetPositionByNode(BinNode root BinNode node ref int pos)
if (root == null)
return false;
if (root == node)
return true;
int temp = pos;
//这么写很别扭 但是能保证只要找到就不再进行下去
pos = temp * ;
if (GetPositionByNode(root Left node ref pos))
return true;
else
//找不到左边找右边
pos = temp * + ;
return GetPositionByNode(root Right node ref pos);
)它们的二进制表示 从左向右逐一比较 直到一个结束或不再相同 则最大的相同子串 就是我们需要得到的最近父亲所对应的位置K
static int FindParentPosition(int larger int smaller)
if (larger == smaller) return larger;
int left = GetLen(larger) &# ; GetLen(smaller);
while (left > )
larger = larger >> ;
left&# ;;
while (larger != smaller)
larger = larger >> ;
smaller = smaller >> ;
return smaller;
static int GetLen(int num)
int length = ;
while (num != )
num = num >> ;
length++;
return length;
)第 次递归遍历 寻找K所对应的节点
函数GetNodeByPosition的思想是 先算出k在第几层power 观察k的二进制表示 比如说 即 从左向右数第一个位 不算 还剩下 表示向右走 表示向左走 于是从root出发 > > >
static BinNode GetNodeByPosition(BinNode root int num)
if (num == ) return root;
int pow = (int)Math Floor(Math Log(num )); // return return return
//第一个位不算
num = << pow;
while (pow > )
if ((num & << (pow &# ; )) == )
root = root Left;
else
root = root Right;
pow&# ;;
return root;
?
?
总结上面的 个步骤
static BinNode FindParentNode(BinNode root BinNode node BinNode node )
int pos = ;
GetPositionByNode(root node ref pos );
int pos = ;
GetPositionByNode(root node ref pos );
int parentposition = ;
if (pos >= pos )
parentposition = FindParentPosition(pos pos );
else //pos <pos
parentposition = FindParentPosition(pos pos );
return GetNodeByPosition(root parentposition);
?
?
如何不用递归实现二叉树的前序/后序/中序遍历?
算法思想 三种算法的思想都是让root的Left的Left的Left全都入栈 所以第一个while循环的逻辑 都是相同的
下面详细分析第 个while循环 这是一个出栈动作 只要栈不为空 就始终要弹出栈顶元素 由于我们之前入栈的都是Left节点 所以每次在出栈的时候 我们都要考虑Right节点是否存在 因为前序/后序/中序遍历顺序的不同 所以在具体的实现上有略为区别
)前序遍历
这个是最简单的
前序遍历是root >root Left >root Right的顺序
因为在第一个while循环中 每次进栈的都可以认为是一个root 所以我们直接打印 然后root Right和root Left先后进栈 那么出栈的时候 就能确保先左后右的顺序
static void PreOrder(BinNode root)
Stack stack = new Stack();
BinNode temp = root;
//入栈
while (temp != null)
Console WriteLine(temp Element);
if (temp Right != null)
stack Push(temp Right);
temp = temp Left;
//出栈 当然也有入栈
while (stack Count > )
temp = (BinNode)stack Pop();
Console WriteLine(temp Element);
while (temp != null)
if (temp Right != null)
stack Push(temp Right);
temp = temp Left;
//后序遍历比较麻烦 需要记录上一个访问的节点 然后在本次循环中判断当前节点的Right或Left是否为上个节点 当前节点的Right为null表示没有右节点
static void PostOrder(BinNode root)
Stack stack = new Stack();
BinNode temp = root;
//入栈
while (temp != null)
if (temp != null)
stack Push(temp);
temp = temp Left;
//出栈 当然也有入栈
while (stack Count > )
BinNode lastvisit = temp;
temp = (BinNode)stack Pop();
if (temp Right == null || temp Right == lastvisit)
Console WriteLine(temp Element);
else if (temp Left == lastvisit)
stack Push(temp);
temp = temp Right;
stack Push(temp);
while (temp != null)
if (temp Left != null)
stack Push(temp Left);
temp = temp Left;
//中序遍历 类似于前序遍历
static void InOrder(BinNode root)
Stack stack = new Stack();
BinNode temp = root;
//入栈
while (temp != null)
if (temp != null)
stack Push(temp);
temp = temp Left;
//出栈 当然也有入栈
while (stack Count > )
temp = (BinNode)stack Pop();
Console WriteLine(temp Element);
if (temp Right != null)
temp = temp Right;
stack Push(temp);
while (temp != null)
if (temp Left != null)
stack Push(temp Left);
temp = temp Left;
?
?
在二叉树中找出和为某一值的所有路径
算法思想 这道题目的苦恼在于 如果用递归 只能打出一条路径来 其它符合条件的路径打不出来
为此 我们需要一个Stack 来保存访问过的节点 即在对该节点的递归前让其进栈 对该节点的递归结束后 再让其出栈——深度优先原则(DFS)
此外 在递归中 如果发现某节点(及其路径)符合条件 如何从头到尾打印是比较头疼的 因为DFS使用的是stack而不是queue 为此我们需要一个临时栈 来辅助打印
static void FindBinNode(BinNode root int sum Stack stack)
if (root == null)
return;
stack Push(root Element);
//Leaf
if (root IsLeaf())
if (root Element == sum)
Stack tempStack = new Stack();
while (stack Count > )
tempStack Push(stack Pop());
while (tempStack Count > )
Console WriteLine(tempStack Peek());
stack Push(tempStack Pop());
Console WriteLine();
if (root Left != null)
FindBinNode(root Left sum &# ; root Element stack);
if (root Right != null)
FindBinNode(root Right sum &# ; root Element stack);
stack Pop();
?
?
?
?
怎样编写一个程序 把一个有序整数数组放到二叉树中?
算法思想 我们该如何构造这棵二叉树呢?当然是越平衡越好 如下所示
//// arr[ ]
//// arr[ ] arr[ ]
//// arr[ ] arr[ ] arr[ ]
相应编码如下
public static void InsertArrayIntoTree(int[] arr int pos ref BinNode root)
root = new BinNode(arr[pos] null null);
root Element = arr[pos];
//if Left value less than arr length
if (pos * + > arr Length &# ; )
return;
else
InsertArrayIntoTree(arr pos * + ref root Left);
//if Right value less than arr length
if (pos * + > arr Length &# ; )
return;
else
root Right = new BinNode(arr[pos * + ] null null);
InsertArrayIntoTree(arr pos * + ref root Right);
?
?
判断整数序列是不是二叉搜索树的后序遍历结果
比如 给你一个数组 int a[] = [ ] 则F(a) => false
算法思想 在后续遍历得到的序列中 最后一个元素为树的根结点 从头开始扫描这个序列 比根结点小的元素都应该位于序列的左半部分 从第一个大于跟结点开始到跟结点前面的一个元素为止 所有元素都应该大于跟结点 因为这部分元素对应的是树的右子树 根据这样的划分 把序列划分为左右两部分 我们递归地确认序列的左 右两部分是不是都是二元查找树
由于不能使用动态数组 所以我们每次递归都使用同一个数组arr 通过start和length来模拟&# ;部分&# ;数组
public static bool VerifyArrayOfBST(int[] arr int start int length)
if (arr == null || arr Length == || arr Length == )
return false;
int root = arr[length + start ];
int i = start;
for (; i < length &# ; ; i++)
if (arr[i] >= root)
break;
int j = i;
for (; j < length &# ; ; j++)
if (arr[j] < root)
return false;
bool left = true;
if (i > start)
left = VerifyArrayOfBST(arr start i &# ; start);
bool right = true;
if (j > i)
right = VerifyArrayOfBST(arr i j &# ; i + );
return left && right;
?
?
求二叉树的镜像
算法 利用上述遍历二叉树的方法(比如说前序遍历) 把访问操作修改为交换左右节点的逻辑
static void PreOrder(ref BinNode root)
if (root == null)
return;
//visit current node
BinNode temp = root Left;
root Left = root Right;
root Right = temp;
PreOrder(ref root Left);
PreOrder(ref root Right);
?
?
算法 使用循环也可以完成相同的功能
static void PreOrder (ref BinNode root)
if (root == null)
return;
Stack stack = new Stack();
stack Push(root);
while (stack Count > )
//visit current node
BinNode temp = root Left;
root Left = root
相关参考
一个算法通常由哪两种基本要素组成?答案一是对数据对象的运算和操作二是算法的控制结构算法的复杂度主要包括什么?答案时间复杂度和空间复杂度实现算法所需的存储单元多少和算法的工作量大小分别称为算法的空间复杂
腾讯算法题服务器内存G有一个G的文件里面每行存著一个QQ号(位数)怎么最快找出出现过最多次的QQ号G内存两个G的文件每个文件格式为每行是一个url地址找出这个两个文件中重复的url地址(典型的url去
(1)一个整数数列,元素取值可能是0—65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻。注意-5个数值
选择排序选择排序的基本思想是对待排序的记录序列进行n遍的处理第i遍处理是将L[in]中最小者与L[i]交换位置这样经过i遍处理之后前i个记录的位置已经是正确的了选择排序是不稳定的算法复杂度是O(n^)
看到一道别人的面试题统计出从n之间的个数如n=f()=>到有个数带有要求不能用字符串方式计算只能用数学方式看回贴都没个答案于是自己也来做做做好了想回贴发现要回答N多问题几十题就懒的点了在自己空间
给一颗二叉树每个节点都有左孩子指针和右孩子指针(当然可能为空)要求给每个节点添加一个指针这个指针要指向它的同一层的紧临的兄弟(要求写代码)给一个单链表将其反转(要求写代码)写一个函数传入一个字符串判断
考试方式闭卷笔试时间为分钟题型结构填空题()多项选择题改错题()程序填空题简答题()编写程序题单项选择题()算法设计题难度结构 本课程考试主要测试考生对数据结构的基本概念基本原理和基本算法的理解掌握
链接表和数组之间的区别是什么?做一个链接表,你为什么要选择这样的方法?选择一种算法来整理出一个链接表。你为什么要选择这种方法?现在用O(n)时间来做。说说各种股票分类算法的优点和缺点。用一种算法来颠倒
.评价好的算法有四个方面一是算法的正确性二是算法的易读性三是算法的健壮性四是算法的时空效率(运行) .()见上面题 ()见上面题 ()见上面题 ()算法的时间复杂性是算法输入规模的函数算法
知识大全 严蔚敏《数据结构(c语言版)习题集》算法设计题第十章答案
第九章查找第十章内部排序 voidInsert_Sort(SqList&L)//监视哨设在高下标端的插入排序算法 k=Llength; for(i=k;i;i)//从后向前逐