//File:: test.cpp
//Author:: Weiqp
//Date:: 2016-6-4
# if 0
# include <iostream>
using namespace std;
void main()
{
int n[][3] = {10,20,30,40,50,60};
int (*p)[3];
p = n;
// 10 20 30
cout<<p[0][0]<<", "<<*(p[0]+1)<<", "<<(*p)[2]<<endl;
}
# endif
//1.二维数组查找(从左下角开始)
# if 0
# include <iostream>
# include <vector>
using namespace std;
bool Find(vector<vector<int> > array,int target)
{
int m,n,x,y;
m = array.size();//行数
n = array[0].size();//列数
x=m-1;y=0;//坐标定在左下角
while(x>=0 && y<=n-1)
{
if(target<array[x][y])
{
x--;//遇小上移
}
else if(target>array[x][y])
{
y++;//遇大右移
}
else {
return true;
}
}
return false;
}
int main()
{
vector<vector<int> > vv(3,vector<int>(4)) ;
int k = 0;
//初始化 vv.size() = 3
for(int i = 0; i<vv.size(); i++)
{
for(int j = 0; j<4; j++)
{
vv[i][j] = k;
k++;
}
}
cout<<vv.size()<<endl;
//输出
for(int i = 0; i<3; i++)
{
for(int j = 0; j<4; j++)
{
cout<<vv[i][j]<<" ";
k++;
}
cout<<endl;
}
if(Find(vv,20))
{
cout<<"OK"<<endl;
}
else
{
cout<<"False"<<endl;
}
}
# endif
//2.替换字符串空格(前提:原数组后有充足的空间容纳多的字符,所以本次并没有分配新的空间)
# if 0
# include <iostream>
using namespace std;
void replaceSpace(char *str,int length)
{
if(str == NULL || length <= 0)
{
return ;
}
int i = 0;
int OriginalLength = 0;
int SpaceCount = 0;
//计算原数组长度和空格数目
while(str[i] != '\0')
{
OriginalLength ++;
if(str[i] == ' ')
{
SpaceCount ++;
}
i++;
}
int NewLength = OriginalLength + 2 * SpaceCount;
if(NewLength < OriginalLength)
{
return ;
}
//IndexOriginal指向原数组末尾,IndexDestination指向新数组末尾
int IndexOriginal = OriginalLength;
int IndexDestination = NewLength;
//从后往前赋值
while(IndexOriginal >= 0 && IndexDestination > IndexOriginal )
{
//替换空格,IndexDestination向前走三步
if(str[IndexOriginal] == ' ')
{
str[IndexDestination --] = '0';
str[IndexDestination --] = '2';
str[IndexDestination --] = '%';
}
else
{
str[IndexDestination --] = str[IndexOriginal];
}
-- IndexOriginal;
}
//打印新数组
int j = 0;
while(str[j] != '\0')
{
cout<<str[j];
j++;
}
cout<<endl;
}
int main()
{
char str[30] = " abc bh hv ";
int length = sizeof(str)/sizeof(str[0]);
replaceSpace(str, length);
return 0;
}
# endif
//3.合并两个有序数组
# if 0
# include <iostream>
using namespace std;
void MergeString(char *str1, char *str2)
{
//判空
if(str1 == NULL || str2 == NULL)
{
return ;
}
int i = 0;
int j = 0;
int Len1 = strlen(str1);
int Len2 = strlen(str2);
/*while(str1[i] != '\0')
{
Len1 ++;
i++;
}
while(str1[j] != '\0')
{
Len2 ++;
j++;
}*/
//定位在str1末尾
int IndexStr1 = Len1 - 1;
//定位在str2末尾
int IndexStr2 = Len2 - 1;
//新数组长度-1,即指向最后一个元素
int NewLen = Len1 +Len2 - 1;
//由后往前将较大的数赋給新数组
while(IndexStr1 >= 0 && IndexStr2 >=0)
{
if(str1[IndexStr1] > str2[IndexStr2])
{
str1[NewLen--] = str1[IndexStr1 --];
}
else
{
str1[NewLen--] = str2[IndexStr2--];
}
}
//将较长数组剩下的元素依次赋給新数组
while(NewLen >= 0 && IndexStr1 >= 0)
{
str1[NewLen --] = str1[IndexStr1 --];
}
while(NewLen >=0 && IndexStr2 >= 0)
{
str1[NewLen --] = str1[IndexStr2 --];
}
return ;
}
int main()
{
char a1[30] = "abcdefgh";//保证有充足的空间容纳a2的元素
char a2[12] = "ijklmonpqrs";
MergeString(a1,a2);
//打印新数组
for(int i = 0; i<20; i++)
{
cout<<a1[i];
}
cout<<endl;
return 0;
}
# endif
//Test
# if 0
# include <iostream>
using namespace std;
int main()
{
char a[20] = "asbvc";
cout<<sizeof(a)/sizeof(a[0])<<endl;//20
cout<<strlen(a)<<endl; //5
return 0;
}
# endif
# if 0
//4.反向打印链表元素
# include <iostream>
# include <stack>
using namespace std;
//定义链表节点
typedef struct ListNode
{
int Value;
ListNode *Next;
};
//方法1::从前往后依次将节点元素压栈然后依次弹出
void PrintListStack(ListNode *Head)
{
stack<ListNode *> s;
if(Head == NULL)
{
return ;
}
ListNode *p = Head;
while(p != NULL)
{
s.push(p);
p = p->Next;
}
while(!s.empty())
{
p = s.top();
printf("%d ",p -> Value);
s.pop();
}
}
//方法2::采用递归,每访问一个节点先输出他的后一个节点,在输出他本身
void PrintListRecur(ListNode *Head)
{
ListNode *p = Head;
if(p != NULL )
{
if(p ->Next != NULL)
{
PrintListRecur(p ->Next );
}
}
printf("%d ",p ->Value );
}
# endif
//5.根据前序遍历和中序遍历重建二叉树
/*思想::
前序遍历的第一个元素一定是根节点,又由中序遍历可知位于根节点前的是左子树元素,
位于根节点后的是右子树元素.按此方法递归建立左子树和右子树。
*/
# if 0
# include <iostream>
using namespace std;
//二叉树结点定义
typedef struct BinaryTreeNode
{
int Value;
BinaryTreeNode *LeftChild;
BinaryTreeNode *RightChild;
};
//构建二叉树
BinaryTreeNode *Construct(int *Preorder, int *Inorder, int Length)
{
if(Preorder == NULL || Inorder == NULL || Length <=0)
{
return NULL;
}
return ConstructCore(Preorder, Preorder +Length -1, Inorder, Inorder +Length -1);
}
//构造函数
BinaryTreeNode *ConstructCore(int *StartPreorder, int *EndPreorder, int *StartInorder, int *EndInorder)
{
//第一个元素作为根节点
int rootvalue = StartPreorder[0];
BinaryTreeNode *root = new BinaryTreeNode();
root ->Value = rootvalue;
root ->LeftChild = root ->RightChild = NULL;
if(StartPreorder == EndPreOrder)
{
if(StartInorder == EndInorder && *StartPreorder == *StartInorder)
{
return root;
}
else
{
throw std::execption("Invalid input.");
}
}
//在中序遍历中找根节点
int *rootInorder = StartInorder;
while(rootInorde <= EndInorder && *rootInorder != rootvalue)
{
rootInorder ++;
}
while(rootInorde == EndInorder && *rootInorder != rootvalue)
{
throw std::execption("Invalid input.");
}
int LeftLength = rootInorder - StartInorder;
int *LeftPreorderEnd = StartPreorder + LeftLength;
//构建左子树
if(LeftLength >0)
{
root ->LeftChild = ConstructCore(StartPreorder +1, LeftPreorderEnd, StartInorder,rootInorder -1);
}
//构建右子树
if(LeftLength < EndPreorder - StartPreorder)
{
root ->RightChild = ConstructCore(LeftPreorderEnd +1, EndPreorder, rootInorder +1,EndInorder);
}
return root;
}
# endif
//6.用两个栈模拟一个队列的操作
/*当要向尾部插入一个节点的时候,将节点依次压入stack1;当要删除头节点的时候,如果stack2为空,则将stack1中的元素依次弹出并压入stack2,这时弹出stack2的栈顶即可;如果stack2不为空,则直接弹出
stack2栈顶*/
# if 0
# include <stdio.h>
using namespace std;
//模板类的定义
template <typename T> class CQueue
{
public:
CQueue(void);
~CQueue();
void appendTail(const T &node);
T deleteHead();
private:
stack<T> stack1;
stack<T> stack2;
};
//向队列插入节点
template <typename T> void CQueue<T>::appendTail(const T &element)
{
stack1.push(element);
}
//删除队头节点
template <typename T> void CQueue<T>::deleteHead ()
{
if(stack2.size() <= 0)
{
while(stack1.size() > 0)
{
T &data = stack1.top();
stack1.pop();
stack2.push(data);
}
}
if(stack2.size() == 0)
{
throw new exception("queue is empty");
}
T head = stack2.top();
stack2.pop();
return head;
}
# endif
//7.用两个队列模拟一个栈的操作
/*思想:
假设有两个队列Q1和Q2,当二者都为空时,入栈操作可以用入队操作来模拟,可以随便选一个空队列,假设选Q1进行入栈操作,现在假设a,b,c依次入栈了(即依次进入队列Q1),这时如果想模拟出栈操作,则需要将c出栈,因为在栈顶,这时候可以考虑用空队列Q2,将a,b依次从Q1中出队,而后进入队列Q2,将Q1的最后一个元素c出队即可,此时Q1变为了空队列,Q2中有两个元素,队头元素为a,队尾元素为b,接下来如果再执行入栈操作,则需要将元素进入到Q1和Q2中的非空队列,即进入Q2队列,出栈的话,就跟前面的一样,将Q2除最后一个元素外全部出队,并依次进入队列Q1,再将Q2的最后一个元素出队即可。
*/
# if 0
# include <iostream>
using namespace std;
template <typename T> void Stack<T>::Push(T elem) //向队列中添加元素
{
if (q1.empty() && q2.empty())
{
q1.push(elem);
}
else if (!q1.empty())
{
q1.push(elem);
}
//q2不为空
else//两个队列不可能同时为空,因为在之前删除元素操作时,有一个必为空队列
{
q2.push(elem);
}
}
template <typename T> void Stack<T>::Pop() //向队列中删除头元素,先进先出
{
if (q1.empty() && q2.empty())//两个队列都为空,无法删除
{
cout<<"queue is empty";
}
if (!q1.empty())
{
while (q1.size()>1)
{
q2.push(q1.front());
q1.pop();
}
q1.pop();
}
//q2不为空
else //if (!q2.empty() && q1.empty())
{
while (q2.size()>1)
{
q1.push(q2.front());
q2.pop();
}
q2.pop();
}
}
# endif
//8.快速排序的实现
# if 0
# include <iostream>
# include <ctime>
using namespace std;
//分割函数
int partition(int *a, int l, int r)
{
srand(time(0));
int i = int(rand() % (r-l+1) + l);//取l~r随机数
int key = a[i];
a[i] = a[l];
//现在key是基数,a[l]留作安放键值
while(l < r)
{
while(l < r && a[r] >= key) r--;
a[l] = a[r];//自右向左找到第一个小于基数的,安放在a[l]
while(l < r && a[l] <= key) l++;
a[r] = a[l];//自左向右找到第一个大于基数的,安放在a[r]
}
a[l] = key;//此时l==r,key左边的值都比它小,右边都比它大
return l;
}
//递归排序
void Qsort(int *a, int l, int r)
{
if(l < r) {
int m = partition(a, l, r);
Qsort(a, l, m-1);
Qsort(a, m+1, r);
}
}
int main()
{
int a[7];
for(int i = 0; i < 6; i++) {
scanf("%d", &a[i]);
}
Qsort(a, 0, 5);
for(int i = 0; i < 6; i++) {
printf("%d ", a[i]);
}
cout<<endl;
return 0;
}
# endif
//9.求旋转数组的最小元素,如[1,2,3,4,5]的一个旋转数组[3,4,5,1,2],最小元素是1.
# if 0
#include <stdio.h>
#include <stdlib.h>
int getMaxIdx(int *A, int len){
int low=0, high=len-1, mid;
while(low<high)
{
mid = low + (high-low + 1)/2;
if(A[mid]>A[low])
low = mid;
else
high = mid-1;
}
return low;
}
int getMin(int *A, int len){
if(A==NULL)
return 0;
int maxIdx = getMaxIdx(A, len);
//最小的数在最大的数后面
int minIdx = (maxIdx + 1)%len;
return A[minIdx];
}
====================测试代码====================
void Test(int* numbers, int length, int expected)
{
int result = 0;
try
{
result = getMin(numbers, length);
for(int i = 0; i < length; ++i)
printf("%d ", numbers[i]);
if(result == expected)
printf("\tpassed\n");
else
printf("\tfailed\n");
}
catch (...)//捕捉任何异常类型
{
if(numbers == NULL)
printf("Test passed.\n");
else
printf("Test failed.\n");
}
}
int main()
{
// 典型输入,单调升序的数组的一个旋转
int array1[] = {3, 4, 5, 1, 2};
Test(array1, sizeof(array1) / sizeof(int), 1);
printf("%d\n",getMin(array1, 5));
// 有重复数字,并且重复的数字刚好的最小的数字
int array2[] = {3, 4, 5, 1, 1, 2};
Test(array2, sizeof(array2) / sizeof(int), 1);
printf("%d\n",getMin(array2, 6));
// 有重复数字,但重复的数字不是第一个数字和最后一个数字
int array3[] = {3, 4, 5, 1, 2, 2};
Test(array3, sizeof(array3) / sizeof(int), 1);
printf("%d\n",getMin(array3, 6));
// 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字
int array4[] = {1, 0, 1, 1, 1};
Test(array4, sizeof(array4) / sizeof(int), 0);
printf("%d\n",getMin(array4, 5));
// 单调升序数组,旋转0个元素,也就是单调升序数组本身
int array5[] = {1, 2, 3, 4, 5};
Test(array5, sizeof(array5) / sizeof(int), 1);
printf("%d\n",getMin(array5, 5));
// 数组中只有一个数字
int array6[] = {2};
Test(array6, sizeof(array6) / sizeof(int), 2);
printf("%d\n",getMin(array6, 1));
// 输入NULL
Test(NULL, 0, 0);
printf("%d\n",getMin(NULL, 5));
system("pause");
}
# endif
//10.输入n,求裴波那挈数列的第n项
# if 0
/*方法1::递归(低效率,树形结构分析会发现有大量重复计算)
f(10) = f(9)+f(8) = f(8)+f(7)+f(7)+f(6).....
*/
long long Fibonacci(unsigned int n)
{
if(n <= 0)
{
return 0;
}
if(n == 1)
{
return 1;
}
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
//方法2::由下往上计算,避免重复f(0)+f(1) = f(2)+f(3) = f(4)...
long long Fibonacci(unsigned int n)
{
int result[2] = {0,1};
if(n < 2)
{
return result[n];
}
long long fiboMinusOne = 0;
long long fiboMinusTwo = 1;
long long fiboN = 0;
for(unsigned int i = 2; i <= n; i++)
{
fiboN = fiboMinusOne + fiboMinusTwo;
fiboMinusOne = fiboMinusTwo;
fiboMinusTwo = fiboN;
}
return fiboN;
}
# endif
剑指Offer算法精炼
最新推荐文章于 2022-09-07 12:39:03 发布