经典算法 1-7
来源:互联网 发布:单片机蓝牙模块怎么用 编辑:程序博客网 时间:2024/05/18 02:53
1.把二元查找树转变成排序的双向链表
题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
10
/ \
6 14
/ \ / \
4 8 12 16
转换成双向链表
4=6=8=10=12=14=16。
首先我们定义的二元查找树节点的数据结构如下:
struct BSTreeNode
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
#include "stdafx.h"
#include <iostream>
using namespace std;
//节点存储结构
struct BSTreeNode
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
typedef BSTreeNode DoubleLink;
DoubleLink * pHead;//头指针
DoubleLink * pListIndex;//每个节点的线索指针
void convertBSTreeToDoubleList(BSTreeNode* pCurrent);
//构造一颗二叉排序树,传入根节点,根据值大小递归找到叶子节点
//主函数需要始终持有根节点指针,根指针本身的值不能改变,因此参数类型为指针类型的引用
void addNodeToBSTree(BSTreeNode* &pCurrent,int nValue)
{
if(pCurrent==NULL)//如果是叶子节点
{
BSTreeNode * pNode=new BSTreeNode();
pNode->m_pLeft=NULL;
pNode->m_pRight=NULL;
pNode->m_nValue=nValue;
pCurrent=pNode;
}
else//如果不是叶子,则向下查找
{
if(pCurrent->m_nValue>nValue)//放到左子树上
{
addNodeToBSTree(pCurrent->m_pLeft,nValue);
}
else
{
addNodeToBSTree(pCurrent->m_pRight,nValue);//放到右子树上
}
}
}
//中序遍历二叉排序树,构造双向链表,递归
void ergodicBSTree(BSTreeNode * pCurrent)
{
if(pCurrent==NULL)
{
return;
}
if(pCurrent->m_pLeft!=NULL)
{
ergodicBSTree(pCurrent->m_pLeft);
}
convertBSTreeToDoubleList(pCurrent);
if(pCurrent->m_pRight!=NULL)
{
ergodicBSTree(pCurrent->m_pRight);
}
}
//将排序二叉树结构转化成双向链表结构,两种数据结构的节点结构相同,只需要更改指针即可
void convertBSTreeToDoubleList(BSTreeNode* pCurrent)
{
pCurrent->m_pLeft=pListIndex;
if(pListIndex!=NULL)
{
pListIndex->m_pRight=pCurrent;
}
else//双向链表还为空
{
pHead=pCurrent;
}
pListIndex=pCurrent;
cout<<pListIndex->m_nValue<<"=";
}
int _tmain(int argc, _TCHAR* argv[])
{
BSTreeNode* pRoot=NULL;
pHead=NULL;
pListIndex=NULL;
addNodeToBSTree(pRoot,10);
addNodeToBSTree(pRoot,6);
addNodeToBSTree(pRoot,4);
addNodeToBSTree(pRoot,8);
addNodeToBSTree(pRoot,14);
addNodeToBSTree(pRoot,12);
addNodeToBSTree(pRoot,16);
ergodicBSTree(pRoot);
return 0;
}
/*
2.设计包含min函数的栈。
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。
要求函数min、push以及pop 的时间复杂度都是O(1)。
*/
/*
解题思路:要求时间复杂度是1,但空间复杂度没有要求。因此可以额外用一个最小值数组栈
记录随着栈的变化最小值索引的变化,两个栈公用一个栈深度,比如:
栈 最小值索引栈
12 4
16 4
8 4
9 3
50 0
22 0
11 0
栈底
*/
#include "stdafx.h"
#include <iostream>
using namespace std;
#define MAX_LEN 100
int stack[MAX_LEN];
int minstack[MAX_LEN];
int stacklen;
//压入栈
void push(int value)
{
if(stacklen>=0&&stacklen<MAX_LEN)
{
stack[stacklen]=value;
if(stacklen==0)
{
minstack[stacklen]=stacklen;
}
else
{
minstack[stacklen]=value<stack[minstack[stacklen-1]]?stacklen:minstack[stacklen-1];
}
stacklen++;
}
else
{
cout<<"栈已满";
}
}
//弹出栈,出栈的时候最小值栈随着stacklen的减小也随之出栈
int pop()
{
int rtn;
if(stacklen>=0)
{
rtn=stack[stacklen--];
return rtn;
}
else
{
cout<<"栈已空";
}
}
//求最小值
int min()
{
return stack[minstack[stacklen-1]];
}
int _tmain(int argc, _TCHAR* argv[])
{
stacklen=0;
push(11);
push(22);
push(50);
push(9);
push(8);
push(16);
push(12);
cout<<min()<<endl;
pop();
cout<<min()<<endl;
pop();
cout<<min()<<endl;
pop();
cout<<min()<<endl;
pop();
cout<<min()<<endl;
return 0;
}
/*
3.求子数组的最大和
题目:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。
*/
#include "stdafx.h"
#include <iostream>
using namespace std;
//求最大和子数组
int maxSumArray(int * a,int n)
{
int temp=a[0];
for(int i=1;i<n;i++)
{
if(temp<a[i])
{
temp=a[i];
}
}
if(temp<0)//如果数组全是负数,那找到最大一个负数即是所求值
{
return temp;
}
int priorsum=0;//先行和,只要和不小于0就加起来,小于0则丢弃从下一个开始
int maxsum=0;//始终保持和最大值。如果先行和大于了maxsum,则交换
for(int j=0;j<n;j++)
{
if(priorsum<0)
{
priorsum=a[j];
}
else
{
priorsum+=a[j];
}
if(maxsum<priorsum)
{
maxsum=priorsum;
}
}
return maxsum;
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[8]={1,-2,3,10,-4,7,2,-5};
cout<<maxSumArray(a,8);
return 0;
}
4.在二元树中找出和为某一值的所有路径
题目:输入一个整数和一棵二元树。
从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。
打印出和与输入整数相等的所有路径。
例如输入整数22 和如下二元树
10
/ \
5 12
/ \
4 7
则打印出两条路径:10, 12和10, 5, 7。
二元树节点的数据结构定义为:
struct BinaryTreeNode // a node in the binary tree
{
int m_nValue; // value of node
BinaryTreeNode *m_pLeft; // left child of node
BinaryTreeNode *m_pRight; // right child of node
};
/*
当访问到某一结点时,把该结点添加到路径上,并累加当前结点的值。
如果当前结点为叶结点并且当前路径的和刚好等于输入的整数,则当前的路径符合要求,我
们把它打印出来。
如果当前结点不是叶结点,则继续访问它的子结点。当前结点访问结束后,递归函数将自动
回到父结点。
因此我们在函数退出之前要在路径上删除当前结点并减去当前结点的值,
以确保返回父结点时路径刚好是根结点到父结点的路径。
不难看出保存路径的数据结构实际上是一个栈结构,因为路径要与递归调用状态一致,
而递归调用本质就是一个压栈和出栈的过程。
*/
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
struct BinaryTreeNode // a node in the binary tree
{
int m_nValue; // value of node
BinaryTreeNode *m_pLeft; // left child of node
BinaryTreeNode *m_pRight; // right child of node
};
//构造二元树
void createBSTree(BinaryTreeNode* &pCurrent, int value)
{
if(NULL==pCurrent)
{
BinaryTreeNode *node=new BinaryTreeNode();
node->m_nValue=value;
node->m_pLeft=NULL;
node->m_pRight=NULL;
pCurrent=node;
}
else
{
if(pCurrent->m_nValue>value)
{
createBSTree(pCurrent->m_pLeft,value);
}
else
{
createBSTree(pCurrent->m_pRight,value);
}
}
}
//1 树的结点指针 2期望和 3 路径栈 4当前和
void findPath(BinaryTreeNode*pCurrent,int expectedSum,std::vector<int> &path,int ¤tSum)
{
if(NULL==pCurrent)
{
return;
}
path.push_back(pCurrent->m_nValue);
currentSum+=pCurrent->m_nValue;
bool isLeaf=pCurrent->m_pLeft==NULL && pCurrent->m_pRight==NULL;
if(currentSum==expectedSum && isLeaf)//找到了满足条件的路径
{
std::vector<int>::iterator iter = path.begin();
for(;iter!=path.end();++iter)
{
cout<<*iter<<'\t';
}
cout<<"the sum is:"<<expectedSum<<endl;
}
if(pCurrent->m_pLeft)
{
findPath(pCurrent->m_pLeft,expectedSum,path,currentSum);
}
if(pCurrent->m_pRight)
{
findPath(pCurrent->m_pRight,expectedSum,path,currentSum);
}
currentSum-=pCurrent->m_nValue;
path.pop_back();
}
int _tmain(int argc, _TCHAR* argv[])
{
BinaryTreeNode* pRoot=NULL;
std::vector<int> v;
int sum=0;
createBSTree(pRoot,10);
createBSTree(pRoot,5);
createBSTree(pRoot,12);
createBSTree(pRoot,4);
createBSTree(pRoot,7);
findPath(pRoot,22,v,sum);
return 0;
}
5.查找最小的k个元素
题目:输入n 个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8 这8个数字,则最小的4 个数字为1,2,3和4。
#include "stdafx.h"
#include <iostream>
using namespace std;
//优化的冒泡排序获得最小的K个最小值。每次把最小的冒泡到最后,
//当得到了第K个最小值时,停止冒泡
void BubbleSortToGetKMin(int r[],int n,int k)
{
int exchange=n;//第一趟冒泡排序的范围是r[0]到r[n]
int num=1;//记录只进行K次冒泡,得到了k个最小值就不需再进行
while(exchange)//仅当上一趟排序有记录交换才进行本趟排序
{
int bound=exchange;
exchange=0;
for(int i=0;i<bound-1;i++)
{
if(r[i]<r[i+1])
{
int t=r[i];
r[i]=r[i+1];
r[i+1]=t;
exchange=i+1;//记录每一次发生记录交换的位置
}
}
cout<<r[n-num]<<endl;
if(num==k)
{
return;
}
num++;
};
}
int _tmain(int argc, _TCHAR* argv[])
{
int r[10]={6,9,2,10,1,26,12,0,39,4};
BubbleSortToGetKMin(r,10,4);//或者最小的4个
return 0;
}
每天一道算法题之6——腾讯笔试题上排数据在下排数据中出现的频率本算法题出自http://blog.csdn.net/v_JULY_v,感谢v_JULY_v
// TopFrequecyInBottom.cpp :定义控制台应用程序的入口点。
//
/*
第6 题
腾讯面试题:
给你10 分钟时间,根据上排给出十个数,在其下排填出对应的十个数
要求下排每个数都是先前上排那十个数在下排出现的次数。
上排的十个数如下:
【0,1,2,3,4,5,6,7,8,9】
举一个例子
数值: 0,1,2,3,4,5,6,7,8,9
分配: 6,2,1,0,0,0,1,0,0,0
0 在下排出现了6次,1 在下排出现了2次,
2 在下排出现了1次,3 在下排出现了0次....
以此类推..
*/
#include "stdafx.h"
#include <iostream>
using namespace std;
#define LEN 10
class FrequencyInButtom
{
private:
int top[LEN];
int buttom[LEN];
bool isSuccess;
public:
FrequencyInButtom();
void setNextRoundButtom();
int* getButtomValues();
};
//构造函数初始化top数组
FrequencyInButtom::FrequencyInButtom()
{
isSuccess=false;
for(int i=0;i<LEN;i++)
{
top[i]=i;
}
}
//设置下一轮的buttom值
void FrequencyInButtom::setNextRoundButtom()
{
bool isOver=true;
for(int i=0;i<LEN;i++)
{
int count=0;
for(int j=0;j<LEN;j++)
{
if(buttom[j]==i)//计算上排数字在下排出现的频率
{
count++;
}
}
if(count!=buttom[i])//如果计算出的频率与下排的对应的值不相等
{
buttom[i]=count;
isOver=false;
}
}
isSuccess=isOver;//如果计算频率与所有的下排对应值相等则成功完成迭代
}
//循环设置bottom的值直至满足条件为止
int* FrequencyInButtom::getButtomValues()
{
while(!isSuccess)
{
setNextRoundButtom();
}
return buttom;
}
//其实题目并不是很难,关键在与要看懂题意,
//要知道经过一定次数的迭代一定可以得到正确结果
int _tmain(int argc, _TCHAR* argv[])
{
FrequencyInButtom * m=new FrequencyInButtom();
int * a=m->getButtomValues();
for(int i=0;i<LEN;i++)
{
cout<<*a++<<endl;
}
return 0;
}
7、1.编程判断俩个链表是否相交
给出俩个单向链表的头指针,比如h1,h2,判断这俩个链表是否相交。
为了简化问题,我们假设俩个链表均不带环。
问题扩展:
1.如果链表可能有环列?
2.如果需要求出俩个链表相交的第一个节点列?
以下是算法实现部分:
如何判断一个单链表是有环的?(注意不能用标志位,最多只能用两个额外指针)
一种O(n)的办法就是
用两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然:
bool check(const node* head)
{
if(head==NULL) return false;
node *low=head, *fast=head->next;
while(fast!=NULL && fast->next!=NULL)
{
low=low->next;
fast=fast->next->next;
if(low==fast) return true;
}
return false;
}
扩展1:如果链表可能有环,则如何判断两个链表是否相交
思路:链表1步长为1,链表2步长为2,如果有环且相交则肯定相遇,否则不相交
list1 head: p1
list2 head: p2
while( p1 != p2 && p1 != NULL && p2 != NULL ) //因为当链表有环但不相交时,此处是死循环。!
{
p1 = p1->next;
if ( p2->next )
p2 = p2->next->next;
else
p2 = p2->next;
}
if ( p1 == p2 && p1 && p2) //相交
else //不相交
//July:如果链表带环但不相交列?此算法,还可行么?
于此,还得好好总结下,问题得这样解决:
1.先判断带不带环
2.如果都不带环,就判断尾节点是否相等
3.如果都带环,那么一个指针步长为1遍历一链表,
另一指针,步长为2,遍历另一个链表。
但第3点,如果带环但不相交,那么程序会陷入死循环。。
所以,此方法只适用于带环且相交的情况下才有用。
问题解决之道:
我们在判断链表带环的时候,用俩指针遍历其中一条链表,若带环则此俩指针将相遇于一节点,
即,据此节点,看在不在另一条链表上。如果在,则相交,如果不在,则不相交。
至此,问题,方才得到较圆满解决。!
1.先判断带不带环
2.如果都不带环,就判断尾节点是否相等
3.如果都带环,判断一链表上俩指针相遇的那个节点,在不在另一条链表上。
如果在,则相交,如果不在,则不相交。
July 2010年10月
-------------------------------
July(786165179) 20:28:53
ei,以俩指针 分别遍历俩个链表时,
俩指针 各自相遇的点,应该可以处在 同一个点吧
July(786165179) 20:30:41
好比,AB一快一慢跑一有圈的跑道
CD 一快一慢也跑一有圈的跑道
如果,这俩跑道 是相同的距离列?
那么 AB CD 相遇的点就一定在同一坐标点了...对吧
July(786165179) 20:31:39
那么,只要找出AB 相遇的点 P,
然后再判断 这个点 P在不在另一条链表上,即ok了。
------------
扩展2:求两个链表相交的第一个节点
思路:在判断是否相交的过程中要分别遍历两个链表,同时记录下各自长度。
Node* step( Node* p, Node* q)
{
if ( !p || !q ) return NULL;
int pLen = 1;
int qLen = 1;
bool result = false;
while( p->next )
{
pLen++;
p = p->next;
}
while( q->next )
{
qLen++;
q = q->next;
}
result = ( p == q );
if ( result )
{
int steps = abs( pLen - qLen);
Node* head = pLen > qLen ? p : q;
while ( steps ) //对齐处理
{
head = head->next, steps--;
}
pLen > qLen ? p = head : q = head;
while ( p != q )
{
p = p->next, q = q->next;
}
reutrn p;
}
return NULL;
}
- 经典算法 1-7
- java 经典算法1
- java经典算法1
- 算法入门经典-1
- 算法竞赛入门经典 例题7-1 最优程序
- 算法竞赛入门经典 习题1-7 打折(discount)
- 经典算法
- 经典算法
- 经典算法
- 经典算法
- 经典算法
- 经典算法
- 经典算法
- 经典算法
- 经典算法
- 经典算法
- 经典算法
- 经典算法
- thread and share variable
- HDU 1128 求是否self-number
- To say "Hello world" in Python CGI Web Programming in 5 minutes
- HTML5安全风险详析之三:WebSQL攻击
- 三层架构:只说明较好,不是非用不可!(1)
- 经典算法 1-7
- loadrunner参数化属性选择
- 活泼好动
- 虚拟化技术初步概念
- S3C6410 FrameBuffer编程(一) ---- 获取屏幕属性
- 伤别
- debug
- 嵌入式系统硬件电路设计时需要考虑的基本问题
- 在windows xp下彻低卸载oracle客户端