#include "sort.h"
#include <iostream>
#include <vector>
using namespace std;
//指针检查为空!!
//指针检查为空!!
//指针检查为空!!
void Josephus(int n,int m)//约瑟夫环 n个人环状每次数到m就出列,少于20人
{ // 如果第一次删除第m个,那么直接把 t 的初值改为m
//int p[20]={0};
int *p = new int[n];
int i,j,t=0;
for (i=0;i<n;i++)
{
p[i]=i+1; //给每个人的编号
}
for (j=n;j>=1;j--) //精彩的地方是这里,安排的巧妙,从n开始,这是人的总数
{
t=(t+m-1)%j; // 输出来的编号 下标,与数组本身的值无关!!
cout<<"输出的编号是:"<<p[t]<<endl; // t 编号 牛逼
for (int k=t;k<n;k++)
{
p[k]=p[k+1];//填补出列的; 从出列的位置开始
}
}
delete[] p;//这里不能忘记!!!!!!!!!!
}
void quick_sort(int *arr,int start,int last)//arr待排序的数组,对区间[l len]之间的数组进行排序
{
int i=start,j=last,temp;//注意数组越界的问题
int tem=arr[start];
if (start<last)
{
//tem=arr[start];
while(i!=j)
{
while(j>i&&arr[j]>tem)//数组越界隐患
j--;
//arr[i]=arr[j];
while(i<j&&arr[i]<tem)
i++;
//arr[j]=arr[i];
if (i<=j)
{
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
//arr[i]=tem;
quick_sort(arr,start,i-1);
quick_sort(arr,i+1,last);
}
}
void select_sort(int arr[],int len)
{
int max=0,temp;
for (int i=0;i<len;i++)
{
max=i;//这里很关键,标识符
for (int j=i+1;j<len;j++)
{
if(arr[j]<arr[max]) //注意这里 i,希望赋给最小值序号
max=j;
}
if (max!=i)//如果max没有变化就说明a[i]是最小值,不用交换
{
temp=arr[i];
arr[i]=arr[max];
arr[max]=temp;
}
}
}
//template<typename Comparable>
void insert_sort(int a[],int len)
{
int j,i,tmp;
int cur=0;
bool state=false;
for (int p=0;p<len-1;p++)
{
//Comparable tem=a[p];
//for (j=p+1;j<a.size();j++)
//{
// if (a[j]>a[p])
// {
// a[p]=a[j];
// cur=j;
// }
//}
//if (tem!=a[p]) //如果执行了if(a[j]>a[p])语句,说明a[p] 发生了变化,说明最大值不是自身
// //,以此为条件判断
//{
// a[cur]=tem;
//}
for (i=1;i<len;i++)
{
tmp=a[i];
j=i-1;
while(j>=0&&tmp<a[j]) //核心代码,移位
{
a[j+1]=a[j];
j--;
}
a[j+1]=tmp;
}
}
}
void shell_sort(int arr[],int len) //也是插入排序的一种,插入排序是一个无序的第一个数
{ //的插入到一个有序的
int temp=0,j;
int gap=len/2;
while(gap>0)
{
for (int i=gap;i<len;i++)
{
temp=arr[i];
j=i-gap;
while(j>=0&&arr[j]>temp)
{
arr[j+gap]=arr[j];
j=j-gap;
}
arr[j+gap]=temp;
}
gap/=2;
}
}
void sift(int arr[],int low,int high)//区间[low,high],不断的构造二叉堆,
{ //大的到根部去,小的到叶子去
int i=low;
int j=2*i;
int temp=arr[i];
while(j<=high)
{
if (j<high&&arr[j]<arr[j+1])
j++;
if (arr[i]<arr[j])
{
arr[i]=arr[j];
i=j;
j=2*i;
}
else break;
arr[i]=temp;
}
for (int i=low;i<=high;i++)
{
cout <<arr[i]<<"\t";
}
cout<<endl;
}
void heap_sort(int arr[],int len)
{
int temp;
sift(arr,1,10);
for (int i=len/2;i>=1;i--)
sift(arr,i,len);
for (int i=len;i>=2;i--)
{
temp=arr[1];
arr[1]=arr[i];
arr[i]=temp;
sift(arr,1,i-1);
}
}
void merge(int arr[],int low,int mid,int high) //区间是arr[low,mid] arr[mid+1,high]
{
int i=low,j=mid+1,k=0;
int *r;
r=(int *)malloc((high-low+1)*sizeof(int)); //别忘了 free 记得以后用new
if (!r) exit(0);
while(i<=mid&&j<=high)
{
if (arr[i]<arr[j])
{
r[k]=arr[i];i++;k++;
}
else
{
r[k]=arr[j];j++;k++;
}
}
while(i<=mid) {r[k]=arr[i];i++;k++;}
while(j<=high) {r[k]=arr[j];j++;k++;}
for (int i=low,k=0;i<=high;i++,k++) //少了个等号=,并且错在arr[i]=r[i]
arr[i]=r[k];
// [9/20/2013 qingezha] 补上
free(r);
}
void merge_pass(int arr[],int length,int n)
{
int i;
for (i=0;i+2*length-1<n;i+=2*length)
merge(arr,i,i+length-1,i+2*length-1);
if (i+length-1<n)
merge(arr,i,i+length-1,n-1);
}
void merge_sort(int arr[],int n)
{
for (int i=1;i<n;i=2*i)
{
merge_pass(arr,i,n);
}
}
int binary_search( int a[],const int n,const int value ) /*二分查找*/
{
int low=0,high=n-1;
int mid=0;
if(a != NULL)
{
while(low<=high)
{
mid=(low+high)/2;//注意可能溢出 low + (high-low)/2
if (a[mid]==value)
return mid;
else if (a[mid]<value)
low=mid+1;
else if(a[mid]>value)
high=mid-1;
}
}
return -1;
}
// [9/20/2013 qingezha] 递归 归并排序
// [start,mid] 和 [mid+1,end] 这两段归并
void merges(int *a,int start,int mid,int end)
{
if(a == NULL || start <0 || mid<0 || end<0) return;
int lengh1 = mid - start + 1;
int lengh2 = end - mid;
int *left = new int[lengh1];
int *right = new int[lengh2];
for(int i=0;i<lengh1;++i)
{
left[i] = a[start + i];
}
for (int i=0;i<lengh2;++i)
{
right[i] = a[mid + 1 + i];
}
int index1=0;
int index2=0;
while(index1<lengh1&&index2<lengh2)
{
if(left[index1]>=right[index2])
{
a[start++]=right[index2++];
}
else
{
a[start++]=left[index1++];
}
}
while(index1<lengh1)
{
a[start++]=left[index1++];
}
while(index2<lengh2)
{
a[start++]=right[index2++];
}
delete [] left;
delete [] right;
}
// [9/20/2013 qingezha] [start,end] 归并
void merges_sort(int *a,int start,int end)
{
if(start<end)
{
int mid=(end+start)/2;
merges_sort(a,start,mid);
merges_sort(a,mid+1,end);
merges(a,start,mid,end);
}
}
void CreatBtree(treePtr &b,char strs[])//叶子节点不进入堆栈
{
BTNode *p,*st[20];
int j=0,top=-1,k=0,i=-1;
while(strs[j]!='\0')
{
switch (strs[j])
{
case '(': k=1; top++;st[top]=p; break;//在这里进栈
case ',': k=2; break;
case ')':top--; break;
default:
{
p=(BTNode *)malloc(sizeof(BTNode));
if (!p) exit(0);
p->ch=strs[j];p->lchild=NULL;p->rchild=NULL;
if (b==NULL)
{
b=p;k=0;
}
switch (k)
{
case 1:st[top]->lchild=p; break;
case 2:st[top]->rchild=p; break;
}
}
}
j++;
}
}
void ShowBtree(treePtr &p)//显示二叉树元素//主要还是思考不全面!!!这是最大的忌讳!!!!!!!!!
{
if (p!=NULL)
{
cout<<p->ch;
if (p->lchild!=NULL||p->rchild!=NULL)//如果这里不加判断,对于A(B(D(G)),C(E,F));这种情况,当循环到G点时
{ //由于G点是叶子结点,if(p!=null)通过,但是同时也输出了'(',')'
cout<<'('; //这样结果就多了与叶子数,相同的括号的对数
ShowBtree(p->lchild); //以后遇到这种情况直接举例说明,临界条件,0,边界,特殊情况
if(p->rchild!=NULL) cout<<',';
ShowBtree(p->rchild);
cout<<')';
}
}
}
void PreOrder(treePtr p)//先序读取二叉树元素 //返回为void 的都可以直接判断 p!=null 但是返回int 就要挨个判断了
{
if (p!=NULL)
{
cout<<p->ch;
PreOrder(p->lchild);
PreOrder(p->rchild);
}
}
void MidOrder(treePtr p)//中序读取
{
if (p!=NULL)
{
MidOrder(p->lchild);
//将二叉查找树转换成双向链表,不能创建任何新的结点,只调正指针方向
cout<<p->ch;
//将这个地方换成接口void ConverToDoublelist(treePtr p)
MidOrder(p->rchild);
}
else
return;
}
void ConverToDoublelist(treePtr pCurrent)//这种需要使用上一次的参数,需要先把上一次的保留下来
{
pCurrent->lchild = plist; // 2 ,因为有了上次保存的结点plist
if (NULL != plist) // 3
{
plist->rchild = pCurrent;
}
else
{
pHead = plist;
}
plist = pCurrent;//第一步写这个 1 因为你下一次调用你还得用上一次的pCurrent
}
void PostOrder(treePtr p)//后序读取
{
if (p!=NULL)
{
PostOrder(p->lchild);
PostOrder(p->rchild);
cout<<p->ch;
}
else
return;
}
void DispLeafs(treePtr p)//显示所有叶子
{
if (p!=NULL)
{
if (p->lchild==NULL&&p->rchild==NULL)
cout<<p->ch;//注意了,别把下面的2行也写到if的语句里了//注意循环
DispLeafs(p->rchild);
DispLeafs(p->lchild);
}
}
/************************************************************************/
/*
如果根为空,返回0;//递归定义
如果根元素为ch,那么返回根所在的层次;
如果根的元素不是ch,那么递归寻找左子树,修改层次值
如果没有找到,那么递归寻找右子树,修改层次值
*/
/************************************************************************/
int Level(treePtr p,char ch,int h)//求出一个二叉树成员ch,在二叉树的层次
{
int cout;
if (p==NULL)
{
return 0; //不存在ch
}
else
{
if (p->ch==ch)//不能和求树的高度混淆了
{
return h;
}
else
{
cout=Level(p->lchild,ch,h+1);//这里特别巧,我还以为要多线程处理,不然h值不唯一
if (cout==0) //每遍历一次数字加一次
{
return Level(p->rchild,ch,h+1);
}
}
}
}
/************************************************************************/
/*
如果根为空,那么返回0;//同样递归定义
如果根不空,求左子树的高度;
求右子树的高度;
取高度的较大值,即为树的高度;
*/
/************************************************************************/
int BtreeHeight(treePtr p)//返回树的高度
{
int le,ri;
if (p==NULL)//又一次将==写成了=;这是一个大忌!!!!!!!
{
return 0;
}
else
{
le=BtreeHeight(p->lchild);
ri=BtreeHeight(p->rchild);
return (le>=ri)?(le+1):(ri+1);
}
}
int BtreeLike(treePtr p,treePtr q)//判断2颗数是否相似,即外形一样,数据可以不一样
{
int left,right;
if (p==NULL&q==NULL)
{
return 1;
}
else if (p==NULL ||q==NULL)
{
return 0;
}
else
{
left =BtreeLike(p->lchild,q->lchild);
right=BtreeLike(p->rchild,q->rchild);//可以这样考虑,假设右子树为空,即返回right==1;
return left & right; //然后left与之相与
}
}
int FindParents(treePtr p,char ch)//查找节点值为ch的所有祖先,我还以为用队列来存储,
{ //没想到这么做,还是递归!!
treePtr q;
if (p==NULL)
{
return 0;
}
else if (p->ch==ch)
{
return 1;
}
else if(FindParents(p->lchild,ch)||FindParents(p->rchild,ch))
{
cout<<p->ch<<" ";
return 1;//这里很关键,递归一定要注意了,要有出口,别忘了写
}
}
void PreOrder1(treePtr p)//先序,不用递归
{
struct
{
treePtr q;//访问的结点
int flag;//标志位,1代表不可访问,0代表可以访问
}st[20];
treePtr mid;
int top=-1;
top++;st[top].q=p;st[top].flag=1;//根进栈
while(top>-1)
{
mid=st[top].q;top--;//根出栈,因为是先序遍历//这里也可以加条件与中序,后序读取一样
if (mid!=NULL) //但是这里不必要,先读根,因为根在堆栈的顶上
{
top++;st[top].q=mid->rchild;st[top].flag=1;//右孩子进栈
top++;st[top].q=mid->lchild;st[top].flag=1;//左孩子进栈
top++;st[top].q=mid;st[top].flag=0;//根进栈,后进先出,先读取根,然后左孩子,最后右孩子
}
if(st[top].flag==0)
{
cout<<st[top].q->ch<<" ";
top--;
}
}
}
void MidOrder1(treePtr p)//中序,不用递归,即左,根 ,右顺序读取
{
struct
{
treePtr q;//访问的结点
int flag;//标志位,1代表不可访问,0代表可以访问
}st[20];
treePtr mid;
int top=-1;
top++;st[top].q=p;st[top].flag=1;//根进栈
while(top>-1)
{
if(st[top].flag==1)
{
mid=st[top].q;top--;//根出栈,因为是中序遍历,注意这里mid,弹出来又进去,主要变化的是flag从1到0
if (mid!=NULL)
{
top++;st[top].q=mid->rchild;st[top].flag=1;//右孩子进栈
top++;st[top].q=mid;st[top].flag=0;//根进栈,后进先出,先读取左孩子,根,最后右孩子
//如果不把mid的flag赋值为0,那么将一直读不出数据
top++;st[top].q=mid->lchild;st[top].flag=1;//左孩子进栈
}
}
if(st[top].flag==0)
{
cout<<st[top].q->ch<<" ";
top--;
}
}
}
void PostOrder1(treePtr p)//后序,不用递归,左 右 根 顺序读取
{
struct
{
treePtr q;//访问的结点
int flag;//标志位,1代表不可访问,0代表可以访问
}st[20];
treePtr mid;
int top=-1;
top++;st[top].q=p;st[top].flag=1;//根进栈
while(top>-1)
{
if (st[top].flag==1)
{
mid=st[top].q;top--;//根出栈,因为序遍历
if (mid!=NULL)
{
top++;st[top].q=mid;st[top].flag=0;//根进栈,后进先出,先读取根,然后左孩子,最后右孩子
top++;st[top].q=mid->rchild;st[top].flag=1;//右孩子进栈
top++;st[top].q=mid->lchild;st[top].flag=1;//左孩子进栈
}
}
if(st[top].flag==0)
{
cout<<st[top].q->ch<<" ";
top--;
}
}
}
// [10/11/2013 qingezha] 完全二叉树第m层第k个节点 都是从0开始 那么保存在数组里面从0开始,到2的m次方+k-1即可得到那个元素
void LeavelOrder(treePtr p)//分层读取,与队列很相像,先读的先入队,从头出队,front==rear循环终止条件
{
const int Maxsize=20;
int front,rear;front=rear=-1;
treePtr qu[Maxsize],q;//Maxsize 可以调整,这里用环形队列,节约资源,
rear=rear+1;qu[rear]=p;//头指针入队列
while(front!=rear)//这里很关键,front 和 rear 指针,环形的,出队 入队相结合
{
front=front+1;//这里别忘了%Maxsize
q=qu[front];//出队列
cout<<q->ch<<" ";
if (q->lchild!=NULL)
{
rear=(rear+1)%Maxsize;//先读取左指针,先入队列,先入队列的先出队列
qu[rear]=q->lchild;
}
if (q->rchild!=NULL)
{
rear=(rear+1)%Maxsize;//后读取右指针,后入队列。符合按层次读取思想
qu[rear]=q->rchild;
}
}
}
treePtr CreatBT1(char *pre,char *mid,int n)//pre先序头指针,mid中序指针,n为结点个数
{ //pre指针的第一个元素为根元素
treePtr s,temp;
char *p=mid;
int k=0,m;
if(n<=0) return NULL;//这里很关键,递归出口
s=(treePtr)malloc(sizeof(BTNode));if (!s) exit(0);
s->ch=*pre;
while(k<n)
{
if (*(p+k)==*pre)
break;
k++;
}
s->lchild=CreatBT1(pre+1,mid,k);//k为左子树的结点个数,n-k+1为柚子树个数,要出去根元素,所以减1
s->rchild=CreatBT1(pre+k+1,mid+k+1,n-k-1);//调整头指针
return s;
}
treePtr CreatBT2(char *post,char *mid,int n)//post后序指针,mid中序指针,n为结点个数
{ //post指针的最后一个元素为根元素
treePtr s;
char *p=mid;
int k=0;
if (n<=0) return NULL;
s=(treePtr)malloc(sizeof(BTNode));if (!s) exit(0);
s->ch=*(post+n-1);
while(k<n)
{
if(*(p+k)==s->ch)
break;
k++;
}
s->lchild=CreatBT2(post,mid,k);//这样将mid分成了两部分,以根元素为分点,分为左右子树
s->rchild=CreatBT2(post+k,mid+k+1,n-k-1);//左右子树,mid 和mid +k +1,post +k
return s;
}
void dijkstra(int v,float adj[][VERTEX_COUNT],float dist[],int prev[])
{
bool s[VERTEX_COUNT]={false};
for (int i=1;i<VERTEX_COUNT;++i) //初始化 prev dist,后面需要使用
{
dist[i] = adj[v][i];
s[i] = false;
if(dist[i] != FLT_MAX)
prev[i] = v; //表示前驱为 源点
else
prev[i] = -1; //表示 无前驱
}
s[v] = true;
dist[v] = 0;
for (int i=1;i<VERTEX_COUNT;++i)
{
float temp = FLT_MAX;
int u = v;
for (int j=1;j<VERTEX_COUNT;++j) //选出最短路径加入集合
{
if(!s[j] && dist[j]<temp)
{
temp = dist[i];
u = j;
}
}
s[u] = true; //加入集合
int newdist = 0;
for (int j=1;j<VERTEX_COUNT;++j) //调正dist[],这些值是只经过s中的点,现在s变化了,所以dist也协同变化
{
if (!s[j] && adj[u][j] != FLT_MAX)
{
newdist = dist[u] + adj[u][j];//很重要的一点,更新dist,只要根据新加入的点 u 来计算,因为以前的点已经计算过了
if(newdist < dist[j])
{
dist[j] = newdist;
prev[j] = u;
}
}
}
}
//////////////////test////////////////////////////////////////////////////////
float dist[VERTEX_COUNT]={0.0};
int prev[VERTEX_COUNT] = {0};
float adj[VERTEX_COUNT][VERTEX_COUNT] = {{0,10,FLT_MAX,30,100},{FLT_MAX,0,50,FLT_MAX,FLT_MAX},
{FLT_MAX,FLT_MAX,0,FLT_MAX,10},{FLT_MAX,FLT_MAX,20,0,60},{FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX,0}};
dijkstra(0,adj,dist,prev);
for(int i=0;i<VERTEX_COUNT;++i)
{
cout<<i+1<<" "<<dist[i]<<"("<<prev[i]+1<<")"<<endl;
}
//////////////////////////////////////////////////////////////////////////
}
void GetNext(Sqstring t,int next[])//获得一个字符串的next数组
{ //如a b c a b c d a e b
int j=0,k=-1; // -1 0 0 0 1 2 3 0 1 0 //即此下标之前匹配的字符个数,默认第0个为-1,1个为0
next[0]=-1;
while(j<t.len-1)
{
if (k==-1||t.data[j]==t.data[k])
{
k++;j++;next[j]=k;
}
else
{
k=next[k];//j+1位置对应要移动的位置
}
}
}
int KMPIndex(Sqstring s,Sqstring t)//s为主串,t为目标串
{
int i=0,j=0,next[10]={0};
GetNext(t,next);
while(i<s.len&&j<t.len)
{
if (j==-1||s.data[i]==t.data[j])//j==-1 1从t头开始匹配,即没有找到pk与pj相同,从头在一一匹配
{
++i;++j;
}
else
{
j=next[j];
}
}
if (j>=t.len)
{
return i-t.len;
}
else
return -1;
}
struct {int i,j;//迷宫的位置
int pre;//迷宫上一块在队列的位置
}qu[50];
int front=-1,rear=-1;//队列头尾节点
//迷宫 堆栈求解,不能求出最优解
int mgpath(int x1,int y1,int x2,int y2)
{
int top=0,i,j,di,find=0;//find 表示是否找到下一个位置(1是)
st[top].i=x1;st[top].j=y1;st[top].di=-1;mg[x1][y1]=-1;//防止重复走一个点,走过的用 -1 标记
while(top>-1)
{
find=0;
i=st[top].i;j=st[top].j;di=st[top].di;
if (i==x2&&j==y2)
{
for (int k=0;k<=top;k++)
{
mg[st[k].i][st[k].j]=5;
}
for (int g=0;g<10;g++)
{
for (int k=0;k<10;k++)
{
cout<<mg[g][k]<<" ";
}
cout<<"\n";
}
cout<<"成功找到一条路";
return 1;
}
while(di<4&&find==0)//一次找到一个就可以,然后跳出循环
{
di++;
switch (di)
{
case 0:i=st[top].i-1;j=st[top].j;break;//因为i,j,是全局变量,很容易被改变,还是用st[top]赋值很放心
case 1:j=st[top].j+1;i=st[top].i;break;
case 2:i=st[top].i+1;j=st[top].j;break;
case 3:j=st[top].j-1;i=st[top].i;break;
}
if(mg[i][j]==0) find=1;
}
if (find==1)
{
st[top].di=di;top++;st[top].i=i;st[top].j=j;st[top].di=-1;mg[i][j]=-1;
}
else
{
mg[st[top].i][st[top].j]=0;top--;
}
}
}
//迷宫 队列求解,可以求出最优解
int mgpath2(int x1,int y1,int x2,int y2)
{
int find=0,i,j;
rear++;qu[rear].i=x1;qu[rear].j=y1;qu[rear].pre=-1;mg[x1][y1]=-1;//加入队列的将mg致1,
while(front<=rear&&find==0)
{
front++;i=qu[front].i;j=qu[front].j;
if (i==x2&&j==y2)
{
int k,sum=front;
find=1;
do
{
k=qu[front].pre;
qu[front].pre=-1;
front=k;
} while (k!=0);
k=0;
while(k<=sum)
{
if(qu[k].pre==-1)
cout<<qu[k].i<<" "<<qu[k].j<<endl;
k++;
}
return find;
}
for (int di=0;di<4;di++)
{
switch (di)
{
case 0:i=qu[front].i-1; j=qu[front].j;break;//因为i,j,是全局变量,很容易被改变,还是用st[top]赋值很放心
case 1:j=qu[front].j+1;i=qu[front].i;break;
case 2:i=qu[front].i+1;j=qu[front].j;break;
case 3:j=qu[front].j-1; i=qu[front].i;break;
}
if(mg[i][j]==0)
{
rear++;
qu[rear].i=i;qu[rear].j=j;qu[rear].pre=front;mg[i][j]=-1;
}
}
}
return find;
}
#include "beauty_of_programming.h"
#include <iostream>
#include <assert.h>
#include <list>
#include <vector>
using namespace std;
//中国象棋将帅问题,A B 所有合法位置,只能使用一个字节存储变量 1.2
void General()
{
struct
{
unsigned char a:4;//在结构体里 a 在8位中的0-3
unsigned char b:4;//b 在4-7,输出时要进行强制转换
} i;
for(i.a=1;i.a<=9;i.a++)
for(i.b=1;i.b<=9;i.b++)
{
if(i.a%3!=i.b%3)
cout<<(int)i.a<<"\t"<<(int)i.b<<endl;//记住这里需要显示的强制转换
}
}
int max(int a,int b)
{
return (a>b)?a:b;
}
int MaxSum(int *a,int n)
{
int start=a[n-1];
int all=a[n-1];
for (int i=n-2;i>=0;i--)
{
start=max(a[i],start+a[i]);//包含a[i]的最大值 ,a[i]后面一段的最大值
all=max(start,all);//
}
return all;
}
int MaxSum2( int *a,int size ) /*数据结构:思想与实现 P14 当检测到一负序列,表示该子序列不可能包含在最大子序列中 */
{ //该算法只适用于序列里面有正有负的情况,全部为负就不行了,全部为负的话,就直接取一个最大值
int thismax=0;
int maxx=0;
int end=0,start=0;
for (int i=0;i<size;i++)
{
thismax+=a[i];
if (thismax>maxx)
{
maxx=thismax;
end=i;
}
else
{
if (thismax<0)
{
thismax=0;
start=i+1;
}
}
}
return maxx;
}
int MaxSum3(int *arr, int lengths) //这个适用于有正有负的数组,全是负的不行!!!
{
int sums= 0;
int next = 0;
for (int i = 0;i < lengths; ++i)
{
if(next <= 0) //连续子数组和小于0,则用下一个元素替代这个字数组和
next = arr[i]; //如果字数组和大于sum,则替代之
else
next += arr[i];
if(sums < next)
sums = next;
}
return sums;
}
// [10/7/2013 qingezha] 给你一个数组,有正有负,返回最大的连续项的乘积
// 如果数组遇到0 则乘积为0,0 和 负数 都比任何一个正数小,那么这种情况下只要取一个最大的连续乘积的正值就可以了
double max_multi_arr(double *arr,int len)
{
if(arr == NULL || len<=0)
return 0.0;
double temp = 1.0;
double sums = arr[0];
for (int i=0;i<len;++i)
{
if(arr[i]!=0) //元素与0 比较
{
temp *= arr[i];
if(temp>sums)
sums = temp;
}
else
{
if(temp>0 && temp>sums)
sums =temp;
temp = 1; //别忘了置0
}
}
return sums;
}
int Cal() /*T=7 */
{
const int INF=-10000;
const int V=64;
const int T=7;
int x=0;
//opt[v][i]表示在第i,i+1,i+2...T-1种饮料中,总容量为v的满意度之和的最大值
int opt[V+1][T+1]={};//购买总容量为V的T类饮料的满意度,
int C[T]={3,2,1,3,2,4,1};//10种饮料,每种饮料的数量的最大值
int v[T]={2,4,8,2,4,8,16};//10中饮料,每种饮料的容积
int H[T]={20,30,25,30,15,30,100};//每种饮料的满意度
for (int i=1;i<=V;i++)
{
opt[i][T]=INF;
}
opt[0][T]=0;
for (int j=T-1;j>=0;j--)
{
for (int i=0;i<=V;i++)
{
opt[i][j]=INF;
for (int k=0;k<=C[j];k++)
{
if(i<k*v[j]) break;
x=opt[i-k*v[j]][j+1];
if (x!=INF)
{
x+=H[j]*k;
if (x>opt[i][j])
{
opt[i][j]=x;
}
}
}
}
}
return opt[V][0];
}
int ElevatorMin()
{
int nperson[11];//共10层,要到 i 层的人数是 nperson[i]
int N1=0;
int N2=nperson[1];
int N3=0;
int minFloors=0;
int targetFloor=1;
for (int i=2;i<11;i++)
{
N3+=nperson[i];//第2层到10层的人数
minFloors+=nperson[i]*(i-1);//要到第2层与第10层的人从1楼到各自楼层所爬的总的层数
}
for (int i=2;i<11;i++)
{
if (N1+N2<N3)
{
minFloors+=N1+N2-N3;
targetFloor=i;
N1+=N2;
N2=nperson[i];
N3-=N2;
}
else
break;
}
return targetFloor;
}
char Find( char *p,int n )
{
int times=0;
char targetch=' ';
for (int i=0;i<n;i++)
{
if (times==0)
{
targetch=p[i];//记录当前猜测水王的ID
++times; //记录水王ID出现的次数
}
else
{
if(targetch==p[i])//如果相同则次数加一
++times;
else
--times;//不同则次数减一,即同时删除这2个不同的ID
}
}
return targetch;
}
int* MaxLen( int *a,const int n) //最长递增子序列的长度 ,没有要求是连续的!!!!!!
{
int len=1;
int lenx=1;
int *Lists=new int[n];
for (int i=0;i<n;i++)
{
Lists[i]=1;len=1;
for (int j=0;j<i;j++)
{
if(a[i]>a[j]) // if(a[i]>a[j] && lists[j]+1>list[i]) lists[i]=lists[j]+1;
{
len=Lists[j];
len++;
}
if(len>Lists[i])
{
Lists[i]=len;
}
}
}
return Lists;
}
// [7/1/2013 qingezha] 找出一个数组中的第二大数,遍历一遍
int Find_Sec_Max( int *a,int n )
{
const int INF=-32767;
int maxnum=a[0];
int secmax=INF;
int temp = 0;
for (int i=1;i<n;i++)
{
/*if (a[i]>maxnum) //方法1
{
secmax=maxnum;
maxnum=a[i];
}
else if(a[i]>secmax)
{
secmax=a[i];
}*/
if (maxnum<a[i]) //方法2
{
temp = maxnum;
maxnum = a[i];
}
if(temp>secmax)
secmax = temp;
}
cout<<"this second maxnum is "<<secmax<<endl;
return secmax;
}
LinkPtr hasCricularLink( LinkPtr & p )//判断有无环,快慢指针,走一步,走两步,相遇,可以求得相遇点
{ //一个从相遇点,另一个从头结点出发,速度一样,相遇的第一点为
LinkPtr slow,fast; //即为环的初始点
fast=slow=p;
if (!p||!fast) return NULL;
while(NULL!=slow)
{
if(NULL==fast->next) return NULL; //如果有环则把环的,则把
fast=fast->next->next;
slow=slow->next;
if(slow==fast) return slow;
}
}
// [10/10/2013 qingezha]寻找上亿数据TOP K
void FindKMax()
{
//for(long i=0;i<1000;i++)
//{
// ofstream outFile; //输出到外存
// outFile.open("D:\\t.txt",ios_base::app);
// srand(i);
// long s=rand()<<6;
// outFile<<s<<" ";
// outFile.close();
//}
//
//system("pause");
// 定义数组存储堆元素
int k;
cin >> k;
long *heap = new long [k+1]; //注,只需申请存储k个数的数组
FILE *fp = fopen("D:\\t.txt", "r"); //从文件导入海量数据(便于测试,只截取了9M的数据大小)
assert(fp);
for (int i = 1; i <= k; i++)
fscanf(fp, "%d ", &heap[i]);
for (int j = 1; j <= k; j++)
cout << heap[j] << " ";
cout << endl;
for (int i=k/2+1;i>=1;--i)
{
siftMaxx(heap,i,k);
}
for (int j = 1; j <= k; j++)
cout << heap[j] << " ";
cout << endl;
long newData;
while (fscanf(fp, "%d", &newData) != EOF)
{
if (newData > heap[1]) //找最小的K个数 如果遇到比堆顶元素kmax更小的,则更新大堆,
{ //找最大的K数,更新小堆
heap[1] = newData;
siftMaxx(heap,1,k); //调整堆
for (int j = 1; j <= k; j++)
cout << heap[j] << " ";
cout << endl;
}
}
for (int j = 1; j <= k; j++)
cout << heap[j] << " ";
cout << endl;
fclose(fp);
system("pause");
}
void siftMaxx( long arr[],int low,int high ) /*区间[low,high],构造二叉堆//大的到根部去,小的到叶子去*/
{
// 这两中方法都可以 ,但是推荐第二种
int i=low;
int j=2*i;
int temp=arr[i];
while(j<=high)
{
if (j<high&&arr[j]>arr[j+1])
j++;
if (arr[i]>arr[j])
{
arr[i]=arr[j];
i=j;
j=2*i;
}
else break;
arr[i]=temp;
}
//////////////////////////////////////////////////////////////////////////
int child;
for (int i=1;i<high;i=child)
{
child=2*i;
if (child+1<=high&&arr[child]>arr[child+1])
++child;
if(arr[child]<arr[i]) //检查是否越界,很多时候的bug最后检查出来都是小毛病,但是浪费了很多时间
//if(child<=high&&arr[child]<arr[i]) 这样就对了
swap(arr[child],arr[i]);
}
}
ptr_has_space head[HASHLEN];//不能在头文件中定义
void write_to_file()//将hash后的结果保存在result.txt中
{
FILE *fp = fopen("D:\\result.txt", "w");
assert(fp);
int i = 0;
while (i < HASHLEN)
{
for (ptr_has_space p = head[i]; p != NULL; p = p->next)
fprintf(fp, "%d %d\n", p->data, p->count);
i++;
}
fclose(fp);
}
void append_hash( const int *p )//附加到hash表中,如果重叠则链表表示
{
int index=hash_function(p);
ptr_has_space q=head[index];
if(NULL==q)
{
head[index]=new node_has_space;
head[index]->count=1;
head[index]->data=*p;
head[index]->next=NULL;
return;
}
else
{
while(q)
{
if(*p==q->data)
{
++(q->count);
return;
}
q=q->next;
}
ptr_has_space pt=new node_has_space;
pt->count=1;pt->data=*p;
pt->next=head[index];//采用头插入法
head[index]=pt;
}
}
int hash_function( const int * p )//简单hash函数
{
int index=0;
if(*p>HASHLEN)
index=*p%HASHLEN;
else
index=*p;
return index;
}
void siftheap( node_has_space arr[],int low,int high )//堆结点类型为node_has_space,筛选
{
int i=low;
int j=2*i;
node_has_space temp=arr[i];
while(j<=high)
{
if (j<high&&arr[j].count>arr[j+1].count)
j++;
if (arr[i].count>arr[j].count)
{
arr[i]=arr[j];
i=j;
j=2*i;
}
else break;
arr[i]=temp;
}
}
void bigDATASearch()
{
//写进数据,模拟上亿的数据
//for(long i=0;i<100000;i++)
//{
// ofstream outFile; //输出到外存
// outFile.open("D:\\t.txt",ios_base::app);
// srand(i);
// long s=rand()%30000;
// outFile<<s<<" ";
// outFile.close();
//}
//
//system("pause");
//将上亿的数据归类,hash,记录重复的次数,然后以<key count> \n 形式写进txt里面
//int *dataptr=new int;
//FILE *fp = fopen("D:\\t.txt", "r"); //从文件导入海量数据
//assert(fp);
//while(fscanf(fp,"%d",dataptr)!=EOF)
//{
// append_hash(dataptr);
//}
//fclose(fp);
//write_to_file();
//system("pause");
//读取上述txt,用堆的形式取前K个count最大值
int k;
cin >> k;
ptr_has_space heap = new node_has_space[k+1]; //注,只需申请存储k个数的数组
FILE *fp = fopen("D:\\result.txt", "r"); //从文件导入海量数据(便于测试,只截取了9M的数据大小)
assert(fp);
for (int i = 1; i <= k; i++)
fscanf(fp, "%d %d", &(heap[i].data),&(heap[i].count));
for (int i=k/2+1;i>=1;--i)
{
siftheap(heap,i,k);
}
for (int j = 1; j <= k; j++)
cout << heap[j].data<<" "<<heap[j].count << " ";
cout << endl;
long newData;
int count;
while (fscanf(fp, "%d %d", &newData,&count) != EOF)
{
if (count > heap[1].count) //找最小的K个数 如果遇到比堆顶元素kmax更小的,则更新大堆,
{ //找最大的K数,更新小堆
heap[1].data = newData;
heap[1].count=count;
siftheap(heap,1,k); //调整堆
for (int j = 1; j <= k; j++)
cout << heap[j].data << "\t"<<heap[j].count<<"\t";
cout << endl;
}
}
for (int j = 1; j <= k; j++)
cout << heap[j].data << " "<<heap[j].count;
cout << endl;
fclose(fp);
system("pause");
}
bool Young( int arr[ROW][COL],int value ) /*找到返回true,否则返回false;*///若小则向下找,若大则向左找
{
int i=0,j=COL-1;
int temp=arr[i][j];
while(1)
{
if (value==temp)
return true;
else if(value>temp&&i+1<ROW)
temp=arr[++i][j];
else if(value<temp&&j>0)
temp=arr[i][--j];
else return false;
}
//测试函数
int arrr[4][4]={{1 ,2 ,8, 9},{2,4,9,12},{4,7,10,13},{6,8,11,15}};
bool res=false;
for (int i=1;i<=15;i++)
{
cout<<i<<" ";
res=Young(arrr,i);
if(res) cout<<"exist"<<endl;
else cout<<"not exist"<<endl;
}
}
void trace_Back( int i,int j,int m[][N+1])
{
if(i==j) return;
trace_Back(i,m[i][j],m);
trace_Back(m[i][j]+1,j,m);
cout<<"A"<<i<<","<<m[i][j]<<"A"<<(m[i][j]+1)<<","<<j<<endl;
}
// [9/15/2013 qingezha]先求出A1*A2 A2*A3 A3*A4 ... 然后3个连乘积,4个连乘积。。。
void matrix_Chain(const int p[N+1],int m[][N+1],int s[][N+1])
{ //然后求出A1*A2*A3 A2*A3*A4...这利用了A1*A2 ,A2*A3
for(int i =1;i<=N;++i) m[i][i]=0;//自身的乘积次数为0
for (int r=2;r<=N;r++)//连续的r个矩阵相乘
{
for (int i=1;i<=N-r+1;i++)//i的界限A1*A2*A3 A2*A3*A4...A6*A7*A8,i为1到6,当4个矩阵连乘积是i从1到5
{ //从而可以知道i的最大值N-r+1
int j=i+r-1;
m[i][j]=m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j]; //如果A为m行*n列,B为n行*l列,那么A*B,总共需要乘积的次数为m*n*l
s[i][j]=i; //从i相连的求得的最小值,如s[1][6]为3,则m[1][6]=m[1][3]+m[4][6],这样递归
for (int k=i+1;k<j;k++)
{
int temp=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if (m[i][j]>temp)
{
m[i][j]=temp;//m[i][j] 即Ai*Ai+1*Ai+2...Aj的总的乘积的次数
s[i][j]=k;//记住最小值k,意思是从i到k然后到j,算出来的最小值
}
}
}
}
for (int i=1;i<N+1;++i)
{
for (int j=1;j<N+1;++j)
{
cout<<m[i][j]<<"\t";
}
cout<<endl;
}
for (int i=1;i<N+1;++i)
{
for (int j=1;j<N+1;++j)
{
cout<<s[i][j]<<"\t";
}
cout<<endl;
}
//矩阵乘积测试用例
int p[7]={30,35,15,5,10,20,25};//共6个矩阵,下标依次是1 2 3 4 5 6
int m[7][7]={0};
int s[7][7]={0};
matrix_Chain(p,m,s);
trace_Back(1,6,s);
}
int recur_matrix_Chain(int i,int j,const int p[N+1],int s[][N+1])//递归求解m[i][j]
{
if(i==j) return 0;
int u=recur_matrix_Chain(i+1,j,p,s)+p[i-1]*p[i]*p[j];
for (int k=i+1;k<j;k++)
{
int temp=recur_matrix_Chain(i,k,p,s)+recur_matrix_Chain(k+1,j,p,s)+p[i-1]*p[k]*p[j];
if(temp<u)
{
u=temp;
s[i][j]=k;
}
}
return u;
}
int memorized_matrix_Chain(int j,int m[][N+1],const int p[N+1],int s[][N+1])//备忘录求解
{
for (int i=1;i<=N;i++)
{
for(int k=1;k<=N;k++)
m[i][k]=0;
}
return lookupChain(1,j,p,s,m);
}
int lookupChain(int i,int j,const int p[N+1],int s[][N+1],int m[][N+1])
{
if (0!=m[i][j]) return m[i][j];//每次查询备忘录,若已经计算过,则直接返回,不用计算
if(i==j) return 0;
int u=lookupChain(i+1,j,p,s,m)+p[i-1]*p[i]*p[j];
for (int k=i+1;k<j;k++)
{
int temp=lookupChain(i,k,p,s,m)+lookupChain(k+1,j,p,s,m)+p[i-1]*p[k]*p[j];
if(temp<u)
{
u=temp;
s[i][j]=k;
}
}
m[i][j]=u;//写进备忘录里面
return u;
//测试用例
int pp[7]={30,35,15,5,10,20,25};//共6个矩阵,下标依次是1 2 3 4 5 6
int mm[7][7]={0};
int ss[7][7]={0};
cout<<memorized_matrix_Chain(6,mm,pp,ss);
}
int Catalan(int n) //卡特兰数 Cn=(1/n+1)(2n,n),(2n,n)为组合数h(0)=1;h(1)=1
{
if(n <= 1)
return 1;
int *h = new int [n+1]; //保存临时结果
h[0] = h[1] = 1; //h(0)和h(1)
for(int i = 2; i <= n; i++) //依次计算h(2),h(3)...h(n)
{
h[i] = 0;
for(int j = 0; j < i; j++) //根据递归式计算 h(i)= h(0)*h(i-1)+h(1)*h(i-2) + ... + h(i-1)h(0)
h[i] += (h[j] * h[i-1-j]);
}
int result = h[n]; //保存结果
delete [] h; //注意释放空间
return result;
}
// [7/7/2013 qingezha] 递归的产生全排列 暂时没弄懂原理
// [9/13/2013 qingezha] 现在已经弄懂了,知道怎么写了,哈哈哈
// 这个接口很重要,对数组arr 下标为k和m之间的元素全排列,思路是这样的:
// 1 递归出口为 k = m 时说明一个全排列已经排好
// 2 从 k 到 m 循环,依次将第一个字符与后面的每一个字符交换,然后全排列后面(k+1,m),然后将交换后的在交换回来,接着交换下一个
void perm(int arr[],int k,int m)
{
if (k==m) //需要判断指针与m,k,提高健壮性
{
for (int i=0;i<m;++i)
{
cout<<arr[i]<<"\t";
}
}
else
{
for(int i=k;i<m;++i) //如1 2 3 4 ;1 和 1 交换,全排列2 3 4
{
swap(arr[k],arr[i]); //交换第k个和从k开始到末尾
perm(arr,k+1,m); //交换后全排列后面的
swap(arr[k],arr[i]);
}
}
}
// [9/13/2013 qingezha] 整数划分问题,比如整数 6 可以划分多少种不同 正整数 相加的情况 //算法设计 王晓东
// 比如和为 n ,最大加数因子为 m ,这样q(n,m)代表划分的种类数,
// q(n,1) = 1,q(1,m) = 1,q(n,n) = q(n,n-1)+1, q(n,m) = q(n,n)(m>n),
// q(n,m)=q(n,m-1)+q(n-m,m)这个牛逼公式
int q(int n,int m)
{
if(n==1||m==1)
return 1;
if(m>n)
return q(n,n);
if(m==n)
return q(n,m-1)+1;
return q(n,m-1) + q(n-m,m);
}
// [9/13/2013 qingezha] 汉罗塔问题 比如 n 个盘子在a上,现在要移动到 b 上,c 是辅助,递归的过程是:如果只有一个盘子可以直接从 a 移到 b
// 如果 n 个,可以先拿 n-1 到 c ,然后将第 n 个移动到 b 中,最后将 n-1 移动到 b 上
void hanoi(int n, int a, int b,int c)
{
if (n>0)
{
hanoi(n-1,a,c,b);
cout<<"from "<<a<<" to "<<b<<endl;
hanoi(n-1,c,b,a);
}
}
// [7/7/2013 qingezha] 动态规划 最长公共子序列 c[i][j]表示Xi={x1,x2,x3。。。xi}与Yj={y1,y2,。。。yj}的最长公共字串序列的长度
int lcs_length(char x[],char y[],int b[LA+1][LB+1],int c[LA+1][LB+1])
{
for (int i=1;i<=LA;++i) c[i][0]=0; //数组需要初始化,否则值不一定
for (int i=1;i<=LB;++i) c[0][i]=0;
for (int i=1;i<=LA;++i)
{
for (int j=1;j<=LB;++j)
{
if (x[i]==y[j]) //序列从1开始计数
{
c[i][j]=c[i-1][j-1]+1;//把c[i][j] 写成了c[i][i]了,重大失误,造成4个小时的浪费
b[i][j]=1; //b记录c的值由哪一个子问题的解得到的
}
else if(c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=2;
}
else
{
c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
////////测试代码//////////////////////////////////////////////////////////////////
for (int i=1;i<=LA;++i) //可以将数据输出来看看,哪里有不符合逻辑的错误
{
for (int j=1;j<=LB;++j)
{
cout<<b[i][j];
}
cout<<endl;
}
cout<<endl;
for (int i=1;i<=LA;++i)
{
for (int j=1;j<=LB;++j)
{
cout<<c[i][j];
}
cout<<endl;
}
cout<<endl;
char x[7+2]=" abcdefx";
char y[7+2]=" aecxdfx";
int b[8][8]={{0}};
int c[8][8]={{0}};
int a[8]={0};
cout<<lcs_length(x,y,b,c)<<endl;
lcs(7,7,x,b);
//////////////////////////////////////////////////////////////////////////
return c[LA][LB];
}
void lcs(int i,int j,char x[],int b[LA+1][LB+1])
{
if(0==i||0==j) return;
if (b[i][j]==1)
{
lcs(i-1,j-1,x,b);
cout<<x[i]<<" ";
}
else if(2==b[i][j])
lcs(i-1,j,x,b);
else lcs(i,j-1,x,b);
}
// [7/8/2013 qingezha] 0-1背包问题 包可以承受的重量为c,物品的重量为w[n+1]=w[1],w[2]w[3]...w[n]
//物品的价值为v[n+1]=v[1],v[2],...v[n],,
//最优值为m[i][j],背包可以承受的重量为j(当前剩余的空间),可以选择的物品为
//i,i+1,i+2...n时0-1背包问题的最优值
//递归表达式 为
// m[n][j]=v[n],if(j>=w[n]);or =0,if(j<w[n])
// m[i][j]=max(m[i+1][j],m[i+1][j-w[i]])+v[i],if(j>=w[i]); or =m[i+1][j] if(j<w[i])
//v 从1开始记数 w也是从1开始记数 分别表示物品的价值和重量 c表示背包的所承受的总重, m表示最优值
//v[6]=v[0],v[1],...v[5],同理w
int knapsack(int v[KIND+1],int w[KIND+1],int c,int m[KIND+1][ALLWEIGHT+1])
{
int maxweight=0;
if(w[KIND]<=c)
maxweight=w[KIND]; //最后一个物品重量
else maxweight=c;
for (int i=0;i<maxweight;++i)
m[KIND][i]=0; //背包空间 < 最后一个物品的重量
//m[KIND][i] = (i<maxweight ? 0: v[KIND]); //这样简洁
for (int i=maxweight;i<=c;++i)
m[KIND][i]=v[KIND];
for (int i=KIND-1;i>=1;--i)
{
maxweight=w[i];
for (int j=0;j<=c;++j)
{
if (j<maxweight)
{
m[i][j]=m[i+1][j];
}
else
{
int m1=m[i+1][j];
int m2=m[i+1][j-maxweight]+v[i];
if (m1>=m2)
m[i][j]=m1;
else
m[i][j]=m2;
}
}
}
return m[1][ALLWEIGHT];
}
void traceback(int m[KIND+1][ALLWEIGHT+1], int w[KIND+1],int c,int x[])
{
for (int i=1;i<KIND;++i)
{
if(m[i][c]==m[i+1][c])
x[i]=0;
else
{
x[i]=1;
c-=w[i];
}
x[KIND]=(m[KIND][c]>0)?1:0;
}
//test
int vv[6]={0,7,9,5,4,6};
int ww[6]={0,9,2,6,5,4};
int cc=ALLWEIGHT;
int xx[6]={0};
int mm[6][ALLWEIGHT+1]={{0}};
cout<<knapsack(vv,ww,cc,mm)<<endl;
traceback(mm,ww,cc,xx);
for (int i=1;i<6;++i)
{
cout<<xx[i]<<"\t";
}
//void fun0(int a[][2])
//{
// cout<<a[0][0];
//}
//void fun1(int (*a)[2])//一个2列的数组,行数不确定,里面存的是int
//{
// cout<<a[0][0];
//}
//void fun2(int **a)
//{
// cout<<a[0][0];
//}
//void fun3(int *a[]) //int * a 一个数组指针,里面的元素是指向整型的指针
//{
// cout<<a[0][0];
//}
}
// [9/16/2013 qingezha]
// 单源最短路径,v为源头,adj为邻接矩阵,其中不属于边集合时设成FLT_MAX,dist为从源头到各个点的距离
// prev 为 dist 路径上的前一个顶点, 默认 v 为 0 即源点
void dijkstra(int v,float adj[][VERTEX_COUNT],float dist[],int prev[])
{
bool s[VERTEX_COUNT]={false};
for (int i=1;i<VERTEX_COUNT;++i) //初始化 prev dist,后面需要使用
{
dist[i] = adj[v][i];
s[i] = false;
if(dist[i] != FLT_MAX)
prev[i] = v; //表示前驱为 源点
else
prev[i] = -1; //表示 无前驱
}
s[v] = true;
dist[v] = 0;
for (int i=1;i<VERTEX_COUNT;++i)
{
float temp = FLT_MAX;
int u = v;
for (int j=1;j<VERTEX_COUNT;++j) //选出最短路径加入集合
{
if(!s[j] && dist[j]<temp)
{
temp = dist[i];
u = j;
}
}
s[u] = true; //加入集合
int newdist = 0;
for (int j=1;j<VERTEX_COUNT;++j) //调正dist[],这些值是只经过s中的点,现在s变化了,所以dist也协同变化
{
if (!s[j] && adj[u][j] != FLT_MAX)
{
newdist = dist[u] + adj[u][j];//很重要的一点,更新dist,只要根据新加入的点 u 来计算,因为以前的点已经计算过了
if(newdist < dist[j])
{
dist[j] = newdist;
prev[j] = u;
}
}
}
}
//////////////////test////////////////////////////////////////////////////////
float dist[VERTEX_COUNT]={0.0};
int prev[VERTEX_COUNT] = {0};
float adj[VERTEX_COUNT][VERTEX_COUNT] = {{0,10,FLT_MAX,30,100},{FLT_MAX,0,50,FLT_MAX,FLT_MAX},
{FLT_MAX,FLT_MAX,0,FLT_MAX,10},{FLT_MAX,FLT_MAX,20,0,60},{FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX,0}};
dijkstra(0,adj,dist,prev);
for(int i=0;i<VERTEX_COUNT;++i)
{
cout<<i+1<<" "<<dist[i]<<"("<<prev[i]+1<<")"<<endl;
}
//////////////////////////////////////////////////////////////////////////
}
// [9/17/2013 qingezha] 和为sum ,加数为 1 到 n,随机选出若干个数,使之和为sum,整数相加,中兴面试
void find_factor(int sums, int n)
{
list<int>list1;
int ie = 1;
// 递归出口
if(n <= 0 || sums <= 0)
return;
// 输出找到的结果
if(sums == n)
{
// 反转list
list1.reverse();
cout<<ie++;
for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)
cout<<" "<< *iter << " + ";
cout << n << endl;
list1.reverse();
}
list1.push_front(n); //典型的01背包问题
find_factor(sums-n, n-1); //放n,n-1个数填满sum-n
list1.pop_front();
find_factor(sums, n-1); //不放n,n-1个数填满sum
}
list<int>list1;
int ie = 1;
// [10/8/2013 qingezha]给定一个数和一个数组,输出这个数组中若干个元素和为给定的那个数的所有情况
void find_factor(int sums, int *arr,int *end)//加数替换为一个数组arr 整数
{
// 递归出口
if(arr == end) //这里很重要,因为整数不像字符串,有'\0'结束标志,
return; //整数没有,所以用arr+sizeof(arr)/sizeof(int)表示地址
// 输出找到的结果
if(sums == *arr)
{
// 反转list
list1.reverse();
cout<<ie++;
for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)
cout<<" "<< *iter << " + ";
cout<<*arr;
cout << endl;
list1.reverse();
}
list1.push_front(*arr); //典型的01背包问题
find_factor(sums-*arr, arr+1,end); //放n,n-1个数填满sum-n
list1.pop_front();
find_factor(sums, arr+1,end); //不放n,n-1个数填满sum
}
///**
//现有整型数组y{1,2,4,3,5,8},写出一个函数,找出所有和为10的集合
//**/
//
//#include <vector>
//#include <iostream>
//#include <algorithm>
//
//void print(std::vector<int>& vec)
//{
// if(!vec.empty())
// {
// std::for_each(vec.begin(),vec.end(),[](const int& val)
// {
// std::cout<<val<<" ";
// }
// );
// std::cout<<std::endl;
// }
//}
//
//void fun(int*begin,int* end,std::vector<int>& vec,int sum)
//{
// if(begin==end && sum==0)
// {
// print(vec);
// }
// else if(begin==end)
// {
// return ;
// }
// else
// {
// if(sum>=*begin)
// {
// vec.push_back(*begin);
// fun(begin+1,end,vec,sum-*begin);
// vec.pop_back();
// }
// fun(begin+1,end,vec,sum);
// }
//}
//
//int main(int argc,char* argv[])
//{
// std::vector<int> vec;
// int arr[]={1,2,4,3,5,8};
// fun(arr,arr+sizeof(arr)/sizeof(int),vec,10);
// system("PAUSE");
// return 0;
//}
// [9/24/2013 qingezha] 有1分 2分 5分 10分无限张,求有多少种组合可以组合成 N 分
// 回溯解空间中寻找答案
int coins[4] = {1,2,5,10};
int total = 0;
vector<int> solution;
int count = 0;
void dfs(int index,int target)
{
if (target == total)
{
++count;
cout<<count<<":";
for(int i=0;i<solution.size();++i)
cout<<solution[i]<<" ";
cout<<endl;
}
if(total>target) return; //总和溢出了,就退回
for (int i=index;i<4;++i) //i 从 index 开始
{
total += coins[i];
solution.push_back(coins[i]); //放进去一个
dfs(i,target); //继续放,然后检查总和是否为target,
solution.pop_back();
total -= coins[i];
}
}
// [9/17/2013 qingezha] 最长递减序列
// 动态规划:待求数组 a[size] ,最长 & 递减,现在用一个数组保存长度,另一个保存最长字母的对应的下一个
// 比如:d[i]表示 a 中 [i,size) 递减序列的最大长度,p[i] 表示 以a[i] 开头的最长递减序列的下一个字符
// d[i] = max{d[k]| i<k<=size-1,a[i]>a[k]} 其中 a[i]>a[k] 很重要
// 如果从前到后比较,需要找到最小的,然后与之比较,找到最小的麻烦;但是从后向前,只要找到最大的,而最大就是下标对应的
void longest_decrease_str(int *a,int size)
{
//这样用size必须是常量!!!!!
//int d[size]; //存储 i-size 之间的最长递减字符串的 长度
//int p[size]; //存储 d[i]=max{d[k]| i<k<=n,a[i]>a[k]}+1,中的k
int *d=new int[size]; //分配内存空间
int *p=new int[size]; //分配内存空间
d[size-1] = 1;
p[size-1] = a[size-1];
int temp = 0;
for (int i=size-2;i>=0;--i)
{
d[i] = 1;
p[i] = -1;
for (int j=i-1;j<size;++j)
{
temp = d[j] + 1;
//p[i] = -1; 这里写就错了,每次循环都付一次值
if(a[i]>a[j] && temp>d[i])
{
d[i] = temp;
p[i] = a[j]; //这里可以换成下标,而不是对应的字符
}
}
}
temp = 0;
int max = 0;
for (int i=0;i<size;++i)
{
if(d[i]>temp)
{
temp = d[i];
max = i;
}
}
int n = 0;
do
{
cout<<a[max]<<" ";
if(n == size-1) break; //这点很重要,记住break,while里面条件不好判断,可以用break
n = max;
while(p[max]!=a[n])
++n;
max = n;
}while(n<size);
delete[] d;
delete[] p;
//test////////////////////////////////////////////////////////////////////////
//int data[10]={9,8,2,5,4,3,2,7,1,0};
//////////////////////////////////////////////////////////////////////////
}
// [9/17/2013 qingezha] 在字符串中找出连续最长的数字串,并把这个串的长度返回,
int continumax(char **outputstr, char *intputstr)
{
char *temp = NULL;
int count = 0;
int length = 0;
while(*intputstr)
{
if(*intputstr>='0'&&*intputstr<='9')
{
temp = intputstr;
while(*intputstr>='0'&&*intputstr<='9')
{
++count;
++intputstr;
}
if (count>length)
{
length = count;
*outputstr = temp;
}
}
count = 0;
++intputstr;
}
return length;
//////////////////////////////////////////////////////////////////////////
//char * p = " ";
//cout<<continumax(&p,"abcd12345ed125ss123456789")<<endl;
//////////////////////////////////////////////////////////////////////////
}
// 如把字符串 abcdef 左旋转 2 位得到字符串 cdefab
// [start,end] 闭区间
void RotateString(char *p,int start,int end)
{
char temp = ' ';
while(start<=end)
{
temp = p[start];
p[start] = p[end];
p[end] = temp;
++start;
--end;
}
}
// 要求时间对长度为 n 的字符串操作的复杂度为 O(n),辅助内存为 O(1)
char* LeftRotateString(char* pStr, unsigned int n)
{
char *temp = pStr;
unsigned int length = 0;
while(*temp)
{
++length;
++temp;
}
if(n>length)
n = n % length;
if(n == 0) return pStr;
RotateString(pStr,0,n-1);
cout<<pStr<<endl;
RotateString(pStr,n,length-1);
cout<<pStr<<endl;
RotateString(pStr,0,length-1);
cout<<pStr<<endl;
return pStr;
//!!!! 这里不能用 char * p ="abcdef",这样p就不能修改里面的字符
//////////////////////////////////////////////////////////////////////////
//char p[7] = "abcdef";
//LeftRotateString(p,2);
//cout<<p;
//////////////////////////////////////////////////////////////////////////
}
//char * strcpy_my(char * dest,char * src)
//{
//
//}
char* strcpy_my(char * dest,char * src) // 实现src到dest的复制
{
if(!src||!dest)
return NULL;
char* stedest = dest; //保存目标字符串的首地址
while ((*dest++ = *src++)!='\0'); //把src字符串的内容复制到dest下
return stedest;
}
// [9/19/2013 qingezha] 洗牌算法
void shuffle(char *p,int length)
{
if (p == NULL || length<=0)
return;
int num = 0;
for (int i=0;i<length;++i)
{
num = rand()%(length - i) + i;
swap(p[i],p[num]);
}
}
// [9/19/2013 qingezha] 腾讯 数组 arr ,然后调整数组每个元素的值 是 其余元素的乘积
// 如a[0] 是a[1]*a[2]*...a[n-1]的乘积,a[1]是a[0]*a[2]*a[3]*...a[n-1]的乘积
void mul_tiplyarr(int *a,int lengths,int *out)
{
int left = 1;
int right = 1;
for (int i=0;i<lengths;++i)
{
out[i] = 1;
}
for (int i=0;i<lengths;++i)
{
out[i] *= left;
out[lengths - 1 - i] *= right;
left *= a[i];
right *= a[lengths - 1 - i];
}
}
// [9/19/2013 qingezha] 随机等概率取数字 取出一个就将后面的往前移动,空出的位置补0
int getNum(int *arr,int lengths)
{
int i = lengths -1;
for (;i>=0;--i)
{
if(arr[i]==0)
continue;
else break;
}
i = rand() % (i+1);
int temp = arr[i];
int j= i;
for (;j<lengths-1;++j)
{
arr[j] = arr[j+1];
}
arr[j]=0;
return temp;
}
// [9/19/2013 qingezha] 单链表递增排序 插入排序 将单链表切开 L->p1->p2->p3...
// 现在 L->p1 然后 r->p2->p3 遍历 r 取第一个元素,然后插入 L 中,相当于插入排序
void sort_singleLinklist(LinkPtr p)
{
LinkPtr temp1 = p; //p1
LinkPtr r = new Node;
LinkPtr temp2;
if (p != NULL)
{
r->next = temp1->next->next; //r 头指针
r->data = 0;
temp1->next->next = NULL; // 链表的next一定要初始化NULL !!!!!!!!!!!!很重要
while(r->next != NULL)
{
temp2 = r->next; //取出第一个指针 注意保留前一个指针temp1->next->data
r->next = temp2->next;
while(temp1->next !=NULL && temp1->next->data < temp2->data)
temp1 = temp1->next;
temp2->next = temp1->next;
temp1->next = temp2;
temp1 = p;
}
}
//////////////////////////////////////////////////////////////////////////
//int p[9] = {25,20,1,18,7,9,2,91,11};
//LinkPtr head = new Node;
//head->next = NULL;
//for(int j=0;j<9;++j)
//{
// LinkPtr t = new Node;
// t->data = p[j];
// t->next = head ->next;
// head->next = t;
//}
//sort_singleLinklist(head);
//LinkPtr pp = head->next;
//while(pp != NULL)
//{
// cout<<pp->data<<" ";
// pp = pp->next;
//}
//////////////////////////////////////////////////////////////////////////
}
int rand7()//随机产生 1-7
{
return rand()%7 +1;
}
int rand10()//利用 rand7() 随机产生 1-10 1-7 那我 用其 -1 后乘以 7,得到0,7,14...42,然后用rand7 相加,弥补其中的空白,就得到 1 - 49 均匀分布,然后取1-40,之后取余即可
{
int i = 0;
do
{
i = (rand7() -1) * 7 + rand7();
} while (i>40);
return i%10 + 1;
}
// [9/22/2013 qingezha] str 中只有英文字母 包括大小写
char* compress_count(char *str,int length)
{
int sum_length = 0;
int re_length = 0;
char ch = ' ';
char *des = new char[length];
while(*str!='\0')
{
*des = *str;
ch = *str;
while(ch == *(++str))
{
++re_length;
}
++des;
if(re_length > 0)
*des = re_length;
re_length = 0;
}
return des;
}
// [9/22/2013 qingezha] 注意指针类型要转换,不能对void 类型进行++运算
// 但当源内存和目标内存存在重叠时,memcpy会出现错误,
// 而memmove能正确地实施拷贝,但这也增加了一点点开销。
void * my_memcpy(void *des, void *src, size_t count)
{
if(des == NULL || src == NULL || count <= 0)
return NULL;
char *dess = (char *)des; //这里要类型转换
char *srcs = (char *)src;
char *ret = dess;
int temp = count;
while(count)
{
*dess++ = *srcs++;
--count;
}
*(ret + temp) = '\0';
return ret;
}
// [9/24/2013 qingezha] 判断地址重叠
void * my_memmov(void *dest, void *src, size_t n)
{
{
char* d = (char*) dest;
const char* s = (const char*) src;
if (s>d) //目的地址在前面,从头复制
{
while (n--)
*d++ = *s++;
}
else if (s<d) //目的地址在后面,从尾部复制
{
d = d+n-1;
s = s+n-1;
while (n--)
*d-- = *s--;
}
return dest;
}
}
// [9/24/2013 qingezha] 寻找大于N的最小的质数
bool isPrime(int num)
{
if(num < 2) return false; //最小的质数是 2
int temp = 2;
while(temp<num)
{
if(num % temp == 0)
return false;
++temp;
}
return true;
}
int largetoNum(int num)
{
if(num <= 0) return -1;
int temp = num + 1;
while(!(isPrime(temp)))
++temp;
return temp;
}
// [9/26/2013 qingezha] 判断是否含有子树
//bool is_subtree(treePtr t1,treePtr t2)
//{
// if (t1 == NULL && t2 == NULL)
// return true;
// else if(t1 != NULL && t2 != NULL)
// {
// if(t1->ch == t2->ch)
// return is_subtree(t1->lchild,t2->lchild) && is_subtree(t1->rchild,t2->rchild);
// else
// return is_subtree(t1->lchild,t2) || is_subtree(t1->rchild,t2);
// }
// else
// return false;
//
//}
// [9/28/2013 qingezha] 数组分割 有2N个数,总和为SUM,现在分割这个数组
// 每个数组的元素的个数为N,且这两个数组的和最接近
// arr为数组指针,length 为数组长度且为偶数,数组下标是从1开始
// d(i,j,s)指 1-i 中选出 j 个数,使其和不大于 s 的最大值
// 动态规划算法:d(i,j,s) 分2 种情况,取arr[i] 与不取 arr[i] 求其最大值
// d(i-1,j,s) 与 d(i,j-1,s-arr[i]) + arr[i] 这2 者比较
#define length 10
#define sum 87
int near_division_arr(int *arr)
{
/*int sum = 0;
for (int i=1;i<length+1;++i)
sum += arr[i];*/ //数组下标不能为变量!!!!!!!!!!!!
int dp[length+1][length/2+1][sum/2+1]; //从长为length的数组中选出length/2个,且使选出来的数字之和不大于sum/2的最大值
memset(dp,0,sizeof(dp)); //初始化为 0
for (int i=1;i<length+1;++i)
{
for (int j=1;j<=min(i,length/2);++j)
{
for (int s=sum/2;s>=arr[i];--s)
{
dp[i][j][s] = max(dp[i-1][j][s],dp[i-1][j-1][s-arr[i]]+arr[i]);
}
}
}
int i = length;
int j = length/2;
int s = sum/2 + 1;
while(i>=1)
{
if(dp[i][j][s] == dp[i-1][j-1][s-arr[i]] + arr[i])
{
cout<<arr[i]<<endl;
--j;
s -= arr[i];
}
--i;
}
return dp[length][length/2][sum/2];
// [9/30/2013 qingezha] 切记 这是动态规划的核心,最优子结构 dp[j-1][s-arr[i]]+arr[i] , dp[j][s],
// 取 N 件物品,总和不超过 sum/2
//int solve2()
//{
// int i , j , s;
// int dp[N+1][SUM/2+2]; //取N+1件物品,总合不超过SUM/2+2,的最大值是多少
// memset(dp,0,sizeof(dp)); //初始状态都为0
// for(i = 1 ; i <= 2*N ; ++i)
// {
// for(j = 1 ; j <= min(i,N) ; ++j)
// {
// for(s = SUM/2+1 ; s >= arr[i] ; --s) //01背包从大到小,可以省空间,即最外层的空间
// {
// dp[j][s] = max(dp[j-1][s-arr[i]]+arr[i] , dp[j][s]);
// }
// }
// }
// //要求最优解则 空间不能优化,
// return dp[N][SUM/2+1];
//}
//int arr[] = {0,1,5,7,8,9,6,3,11,20,17};
//const int NN=5; //元素个数
//const int SUM = 87;
//int solve2()
//{
// int dp[NN+1][SUM/2+1];
// memset(dp,0,sizeof(dp));
// for (int i=1;i<=NN;++i)
// {
// for (int j=1;j<=min(i,NN);++j)
// {
// for (int s=SUM/2;s>=arr[i];--s)
// {
// dp[j][s]=max(dp[j][s],dp[j-1][s-arr[i]]+arr[i]);
// }
// }
// }
// return dp[NN][SUM/2];
//}
//int solve3()
//{
// int i , j , s;
// int isOK[N+1][SUM/2+2]; //isOK[i][v]表示是否可以找到i个数,使得它们之和等于v
// memset(isOK,0,sizeof(isOK)); //都不合法
// //注意初始化
// isOK[0][0] = 1; //可以,取0件物品,总合为0,是合法的
// for(i = 1 ; i <= 2*N ; ++i)
// {
// for( j = 1 ; j <= min(i,N) ; ++j)
// {
// for(s = SUM/2+1 ; s >= arr[i] ; --s) //从大到小,数组少了一维
// {
// if( isOK[j-1][s-arr[i]] )
// isOK[j][s] = 1;
// }
// }
// }
// for(s = SUM/2+1 ; s >= 0 ; --s)
// {
// if(isOK[N][s])
// return s;
// }
// //要求最优解则空间不能优化
// return 0;
//}
}
long StringToInt(char *ch) //功能测试,边界测试,负面测试(不符合常规代入参数)
{ // 前面带 ‘+’ ‘-’代表正负,还有字符中出现字母需要判断
if(!ch) return -1; // 就是不是数字的字符
long num = 0;
bool isPositive = false;
if(*ch == '+') //
{
isPositive = true;
++ch;
}
else if(*ch == '-') //
{
isPositive = false;
++ch;
}
while(*ch)
{
if('0'<=*ch && *ch<='9') // '0'<=*ch<='9' 这样写就是 或 的关系
{
num = num * 10 + (*ch - '0');
++ch;
}
else
return -1;
}
return isPositive ? num : -num ; //前面是bool 若真整体的值就是num,即前者
}
// [9/29/2013 qingezha] 正数的开方 主要采用二分法,一个为0.0001 ,另外一个为value
// mid 为二者的平均值,如果平均值的平方大于value则mid取上一次mid和0.0001之间的平均值
float my_sqrt(float value)
{
float low = 0.0000001;
float high = value>1?value:value+1;
float mid = 0.0;
float min = 0.0;
do
{
mid =(high + low)/2;
min = mid * mid;
if(min>value)
high = mid;
else
low = mid;
} while (abs(value - min)>=0.000001);
return mid;
}
// [9/30/2013 qingezha] // lowbit表示的是某个数从右往左扫描第一次出现1的位置
int lowbit(int x)//输出x 的低位中的第一个1 位置
{
return x&~(x-1); //x 与 负x 相与 找到
}
void find(int *arr,int len)
{
int xor = 0;
int flips = 0;
for (int i=0;i<len;++i)
xor ^= arr[i];
// 三个数两两的异或后lowbit有两个相同,一个不同,可以分为两组 //正确
for(int i=0;i<len;++i)
flips ^=lowbit(xor ^ arr[i]);
// 表示的是:flips=lowbit(a^b)^lowbit(a^c)^lowbit(b^c)
int b = 0; // 假设三个只出现一次的其中一个数为b
for(int i=0;i<len;++i)
if(xor ^ arr[i] == flips)
b = arr[i];
cout<<b<<endl;
//////test/////////////////////////////////////////////////////////////////
//int arr[] = {1,5,7,1,5,7,12,11,13}; //共 11 个
//find(arr,9);
//////////////////////////////////////////////////////////////////////////
}
// [9/30/2013 qingezha] Union-Find 并查集
// 初始化所有的结点用整数表示,比如(0--n-1),在处理输入pair之前,他们分属于不同的组,每个结点都是孤立的
// 可以用数组表示这种关系,数组的index表示结点,而对应的值表示组号
int const NODE_NUM = 1001;
int count_set = NODE_NUM;
int arr[NODE_NUM]={0};
void UF_init() //初始化
{
for (int i=0;i<NODE_NUM;++i)
arr[i] = i;
}
int find(int p) //查找这个结点属于 哪个组
{
if(p>=0&&p<NODE_NUM)
return arr[p];
else
return -1;
}
bool connect(int p,int q) //判断是否连接
{
if(p>=0 && p<NODE_NUM && q>=0 && q<NODE_NUM)
return arr[p]==arr[q];
else
return false;
}
int count() //组的个数
{
return count_set;
}
bool union_two(int p,int q) //合并2个,使之为一个组
{
if(p>=0 && p<NODE_NUM && q>=0 && q<NODE_NUM)
{
if(arr[p]==arr[q])
return true;
else
for(int i=0;i<NODE_NUM;++i)
if(arr[i]==arr[p])
arr[i] = arr[q];
--count_set;
return true;
}
else
return false;
}
// [10/7/2013 qingezha].给定一个源串和目标串,能够对源串进行如下操作:
// 1).在给定位置上插入一个字符
// 2).替换任意字符
// 3).删除任意字符
// 写一个程序,返回最小操作次数,使得对源串进行这些操作后等于目标串。
// 例如:源串”hello”,目标串”lleo”,则通过3次修改可以使得源串变成目标串(删除’h',删除’e',在’o'之前插入字符’e')
//也可以通过找到最长公共字串,然后2个原来串的长度和减去公共字串的长度即可
//用f[i][j]表示要修改的最少次数 源头x[1...i] 目标y[1...j],如果x[i]==y[j] 则f[i][j]=f[i-1][j-1]
//如果不同,则可以用增,删,改,分别对应的f[i][j-1]+1,f[i-1][j]+1,f[i-1][j-1]+1,
int cal_distance(const char *sta,const char *stb)
{
if(sta == NULL || stb == NULL)
return 0;
int f[10+1][5+1]={0}; //这里可以用new一个一维数组,代替栈上的二维数组,因为栈上的编译时就确定长度,堆上的运行时才确定
//这里纯用于测试
for (int i=0;i<11;++i)
f[i][0]=i; //悲剧啊,这里误写成0 了
for (int i=0;i<6;++i)
f[0][i]=i; //悲剧啊,这里误写成0 了
int temp = 0;
for (int j=1;j<6;++j)
{
for (int i=1;i<11;++i) //j<6写成了i<6,以后要小心啊
{
if(sta[i]==stb[j])
f[i][j]=f[i-1][j-1];
else
{
temp = min(f[i-1][j-1]+1,f[i-1][j]+1);//这里是增,删,改对应的次数
f[i][j]=min(f[i][j-1]+1,temp);
}
cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
}
}
return f[10][5];
}
// [9/30/2013 qingezha] 链表倒置 循环与递归形式
// 一般形式,1—>2->3->4 现在1<-2<-3<-4 那么改变1的next的时候需要保存指向2的指针,然后同理处理2
// 需要保存的,用直译(见词知意)的表达出来比如:pre前面,next后面,cur当前,然后循环后赋新值
LinkPtrs reverse_link(LinkPtrs root) //头指针指向的是第一个元素
{
if(root == NULL)
return NULL;
LinkPtrs nextp = root->next; //第一个结点
LinkPtrs pre = root; //保留前端
LinkPtrs temp = NULL;
LinkPtrs reverseHead = NULL;
pre -> next = NULL;
while(nextp->next)
{
temp = nextp -> next; //先要保存下一个指针
nextp -> next = pre;
pre = nextp;
nextp = temp;
}
nextp -> next = pre;
reverseHead = nextp;
return reverseHead;
}
//链表倒置,切记 方法很巧!!!!!!!!!!!!!!!!!!
LinkPtrs reverse_link_recursive(LinkPtrs root)
{
if(root == NULL)
return NULL;
LinkPtrs cur,temp,revers_head;
if(root->next == NULL)
return root; //链表如果只有一个结点,那么直接返回第一个
else
{
cur = root;
temp = cur -> next; //temp 为2->3->4的头指针
//可以认为后面的都已经倒过来了,且认为revers_head 为倒过来的链表的头指针
//这样理解就容易多了
revers_head = reverse_link_recursive(temp);
temp -> next = cur;
cur -> next = NULL;
}
return revers_head;
}
// [9/30/2013 qingezha]实现一个函数,对一个正整数n,
// 算得到1需要的最少操作次数。操作规则为:如果n为偶数,将其除以2;如果n为奇数,可以加1或减1;一直处理下去。
//奇数的时候加1或减1,完全取决于二进制的后两位,如果后两位是10、00那么肯定是偶数,选择除以2,
//如果后两位是01、11,那么选择结果会不一样的,如果是*****01,那么选择减1,如果是*****11,那么选择加1,
//特殊情况是就是n是3的时候,选择减1操作。
int func(unsigned int n)
{
if(n==1)
return 1;
if(n%2==0)
return 1 + func(n/2);
if(n==3)
return 2; //3到1 共2步,先-1 后除以2,
if(n&2)
return 1 + func(n+1);
else
return 1 + func(n-1);
}
// [10/2/2013 qingezha] 数组子序列的个数,4,14,2,3和14,1,2,3都为4,13,14,1,2,3的子序列。 对于给出序列a,有些子序列可能是相同的,这里只算做1个,要求输出a的不同子序列的数量。
// 用一个数组记录出现2次或2次以上的数字,离当前数字最近的相同的数字的下标
// 比如1 2 3 4 2,一开始都为0,然后下标一次变为1 2 3 4,到新2 的时候 因为有2,所以要找到这个2的下标,才可以运算那个式子
// 所以用last_index记录数字的下标,里面是对应的arr[i],即要找的值2
#define Mod 1000000007
long sub_sequence(int *arr,int len) //整数数组不能检查越界,要已知长度
{
long sub_arr[120] = {0};
int last_index[120] = {0}; //初始值这里设的好
for (int iter=1;iter<=len;++iter)
{
switch(last_index[arr[iter-1]])
{
case 0:
{
sub_arr[iter] = 2 * sub_arr[iter-1]+ 1;
break;
}
default:
{
sub_arr[iter] = 2 * sub_arr[iter-1] - sub_arr[last_index[arr[iter-1]]-1];//上一个相同的数字的下标
}
}
last_index[arr[iter-1]] = iter; //这里写错了last_index[iter-1],每一次都更新,按次序递增
}
return sub_arr[len]; //这里写错了 sub_arr[len-1]
//////test///////////////////////////////////////////////////////////////////
//int arr[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
//cout<<sub_sequence(arr,sizeof(arr)/sizeof(int));
//////////////////////////////////////////////////////////////////////////
}
// [10/3/2013 qingezha]已知线段长度,求覆盖最多的点数,(一个有序数组代表各个点)
int calculate_num(int *arr,int length,int seg_len)
{
if(arr == NULL||length<=0 || seg_len<=0)
return 0;
int rear = length - 1;
int front = 0;
int max_num = 0;
while(rear>=0) //从最后一个点出发,依次减去前面的点的值,判断差值,然后记录点的个数
{
front = rear;
while(front>=0)
{
if((arr[rear]-arr[front])<=seg_len)
--front;
else //这里要记住,跳出循环
break;
}
//换成while((arr[rear]-arr[front])<=seg_len) 更简洁
max_num = rear-front > max_num ? rear - front : max_num; //这里三元操作运算符
--rear;
}
return max_num;
//////////////////////////////////////////////////////////////////////////
// int arr[5] = {1,2,5,6,9};
// cout<<calculate_num(arr,5,2);
//////////////////////////////////////////////////////////////////////////
}
// [10/3/2013 qingezha] 真没想到可以从中间向两边出发,分别比较2边是否相同,注意回文个数是偶数/奇数情况
int getpalindrome(char *arr,int len)//获取最大的回文
{
int i = 0;
int j = 0;
int max = 0;
for (i=0;i<len;++i)
{
for(j=1;i+j<len&&i-j>=0;++j) //回文是奇数的情况
if(arr[i-j] !=arr[i+j])
break;
if(2*j-1>max)
max = 2*j - 1;
for (j=1;i-j>=0&&i+j+1<len;++j) //回文长度为偶数,认为与相邻的后面相同
if(arr[i-j]!=arr[i+j+1])
break;
if(i+j+1==len&&2*j + 2>max)
max = 2*j + 2;
if(i+j+1==len&&2*j - 2>max) //这里j在元素不等时跳出与for中条件不满足时跳出
max = 2*j - 2;
}
return max;
}
//另外一种方法是abcgoogleaba,可以进行这样的操作:#a#b#c#g#o#o#g#l#e#a#b#a#
//中间插入#或其他字符
int getpalindrome_ss(char *arr,int len)//获取回文的最大长度
{
int len2 = 2*len + 1;
int j = 0;
int i = 0;
int max = 0;
char *str = new char[len2];
for (int i=0;i<len;++i)
{
str[2*i] = '#';
str[2*i+1] = arr[i];
}
str[len2-1] = '#'; //中间插入“#”
for(i=0;i<len2;++i)
{
for(j=1;i+j<len2&&i-j>=0;++j)
if(arr[i-j] !=arr[i+j])
break;
if(2*j-1>max)
max = 2*j - 1;
}
delete[] str;
return max;
}
void get_n()
{
int num = 20; //控制输出个数
int i = 1;
int temp = 0;
while(1)
{
if(temp%3==2&&temp%5==3&&temp%7==2)
{
cout<<i<<" "<<temp<<endl;
++i;
if(i>num)
break;
}
++temp;
}
}
// [10/10/2013 qingezha]最长相同字符
int large_same(char *arr)
{
if(arr == NULL)
return -1;
int count = 0;
int max1 = 1;
while(*(arr+1)!=0 && *arr == *(arr+1))
{
++arr;
++max1;
}
if(*(arr+1)==0)
return max1; //这里出口很重要!!!!可以举例,比如aabb带进去试试,看看有没返回值
int max2 = large_same(++arr); //别忘 了 是++,就是下一个
return max2>max1?max2:max1;
}
// [10/10/2013 qingezha]没有重复出现的数字
unsigned int GetNotRepeatNum(unsigned int lValue)
{
int count[10]={0};
int temp = lValue;
int index = 0;
int i = 0;
bool isfind = true; //初始值为false 错了
while(1)
{
while(lValue>0) //这里出口1
{
index = lValue % 10;
count[index]++;
//if(count[index]>1) //这里出口2
// break;
lValue = lValue/10;
}
for (i=0;i<10;++i)
if(count[i]>1) //只要有一个就为false,就跳出
{ //另外跳出也有i<10的可能
isfind = false;
break;
}
//else
// isfind = true; //这里没写,错了
for (int i=0;i<10;++i)
count[i] = 0;
if(!isfind) //通过break出口
lValue=++temp;
if(i==10) //通过i<10出口
return temp;
}
}
// [10/6/2013 qingezha]遍历一个文件,里面元素个数不知道,让你设计一个算法遍历一遍,等概率的随机取出一个元素
// 可以这样:设现在遍历到第 i 个元素,现在判断如果 rand()%i为0则将返回值更新为第i个元素;否则不变
char get_equal_char(char *arr)
{
if(arr == NULL)
return NULL;
int i = 1;
char re_char = arr[0];
char *temp = arr;
while(*arr)
{
if(rand()%i==0) //这里牛逼
re_char = arr[i-1];
++i;
++temp;
}
return re_char;
}
// [10/7/2013 qingezha] 求出1…n之间的所有亲和数。
// 所谓亲和数,即存在数a和数b,a的所有真因子之和等于b,b的所有真因子之和等于a,则称a和b为一对亲和数。
// 例如220的真因子为:1、2、4、5、10、11、20、22、44、55、110,和为284;而284的真因子为:1、2、4、71、142,和正好为220。故220和284是一对亲和数。
// 现在设j 的真因子和为sum[j],那么j 可以被所有的因子整除的和为sum[j] ,其中可以整除就是关键
void print_Affsum(int n)
{
if(n<=0)
return;
int *sum = new int[n+1];
for (int i=1;i<n+1;++i)
sum[i]=1; //所有亲和数都有因子 1
for (int i=2;i<n/2;++i) //i 作为因子,所以最大也只能为 n/2
{
for (int j=2*i;j<n+1;j+=i)//j 为可以整除 i,所以递增为 i
{
sum[j] += i;
}
}
int i = 1;
while(i<n+1)
{
if(sum[i]<n+1&&i==sum[sum[i]]) //这里别忘记检测sum[i]的值,因为sum[sum[i]]可能越界
cout<<i<<" "<<sum[i]<<endl;
++i;
}
delete[] sum;
}
// [10/7/2013 qingezha]给出一个整型数组num[],和一特定值x,判断数组中是否存在一个或若干个元素之和为x,若存在则返回true,否则false。
bool is_sum(int *arr,int len,int x)
{
if(arr==NULL||len<1)
return false;
if(len==1)
return arr[0] == x; //如果有,要么等于x,要么<= x-arr[i]
for (int i=0;i<len;++i)
{
if (arr[i]==x||is_sum(arr+i+1,len-i-1,x-arr[i]))
return true;
}
return false;
}
// [10/10/2013 qingezha] 给出一个整型数组num[],对其中的每个元素,输出在它左侧且比它小的最近元素,
// 要求时间复杂度为O(n)。例如int num[]={2,4,1,3},2无左侧最近元素;4左侧最近的是2;1没有;3左侧最近的是1.(百度面试题)
// 输出每个元素中,在它左侧且比它小的最近元素
void PrintEachMin(int num[], int len)
{
if(!num || len<=0)
return ;
stack<int> sta;
// 对每个元素,进栈前先循环判断栈顶是否比它大,若是则该元素就是栈顶的左侧最近小元素
// 此时输出结果后,弹出栈顶元素。最后将该元素压入栈
for (int i=len-1; i>=0; --i){
while(!sta.empty() && num[i]<sta.top()){
printf("The nearest number of %d is %d!\n", sta.top(), num[i]);
sta.pop();
}
sta.push(num[i]);
}
// 此时栈中的所有元素均不存在左侧最近小元素
while(!sta.empty()){
printf("%d haven't nearest number!\n", sta.top());
sta.pop();
}
}
// [10/14/2013 qingezha]百钱买百鸡 公鸡5元 母鸡3 3只小鸡1,100买100只
void mai_ji()
{
int num =0;
int sum =0;
for (int i=0;i<120;++i)
{
for (int j=0;j<133;++j)
{
for (int k=0;k<133;++k)
{
num = i+j+k*3;
sum = 5*i+3*j+k;
if(num==sum&&num==100)
cout<<i<<" "<<j<<" "<<3*k<<endl;
}
}
}
}
#include "empress.h"
#include <iostream>
using namespace std;
int qq[20]={0};//用于保存皇后所在的行数,从第一列开始存皇后所在的行数
int find(int i,int j)//判断i行j列是否合法
{
int k=1;
while(k<j)
{
if (qq[k]==i||abs(qq[k]-i)==abs(k-j))
{
return 0;
}
k++;
}
return 1;
}
void place(int k,int n)
{
if (k>n)
{
for (int i=1;i<=n;i++)
{
cout<<qq[i]<<" ";
}
cout<<endl;
}
else
{
for (int j=1;j<=n;j++)
{
if (find(j,k))
{
qq[k]=j;place(k+1,n);
}
}
}
}
// [10/2/2013 qqingezha]
int finds(int i,int j)//第i 行,第j 列 是否合法
{
int temp = 1; //temp 列,qq[列] = 行
while(temp<j)
{
if(abs(j-temp) == abs(i-qq[temp])||qq[temp]==i)//这个忽略了;可能在同一行
return 0;
++temp;
}
return 1;
}
void places(int k,int n) //第k个皇后,k从1开始
{
if (k > n)
{
FILE *fp = fopen("D:\\t.txt", "a");
for (int i=1;i<=n;++i)
fprintf(fp, "%d ", qq[i]);
fprintf(fp,"\n");
fclose(fp);
}
else
{
for(int j=1;j<=n;++j) //行
if(finds(j,k))
{
qq[k] = j;
places(k+1,n);
}
}
}