关于算法,在这里给出我们常用的几个算法:
◆合并排序,将两个已经排序的数组合并成一个数组,其中一个数组能容下两个数组的所有元素;
◆合并两个单链表;
◆倒序打印一个单链表;
◆给定一个单链表的头指针和一个指定节点的指针,在O(1)时间内删除该节点;
◆找到链表倒数第K个节点;
◆反转单链表;
◆通过两个栈实现一个队列;
◆二分查找;
◆快速排序;
◆获得一个int型的数中二进制中1的个数;
◆输入一个数组,实现一个函数,让所有奇数都做偶数前面;
◆判断一个字符串是否是另一个字符串的子串;
◆把一个int型数组中的数字拼成一个串,这个串代表的数字最小;
◆输入一颗二叉树,输出它的镜像(每个节点的左右子节点交换位置);
◆输入两个链表,找到它们的第一个公共节点;
声明,每个算法可能都有多种实现的思路,这里小编只对问题分解,写了自己的思路,如果大家有意见或者更好的方法欢迎交流,谢谢,勿喷。。。
一、合并排序,将两个已经排序的数组合并成一个数组,其中一个数组能容下两个数组的所有元素
1、假设两个数组都是升序排列,合并之后的数组也是升序;
2、两个数组的数据从后开始两两比较,最开始a[Max]与b[Max]比较,假设a[Max]小,那么a[Max]成为新数组元素,a[Max-1]与b[Max]继续比较较小值;
3、两数组中有一个数组先完成了排序,那么把另一个数组剩下的数据按由小到大填充到新数组后续空间里;
程序代码并附上运行结果:
/************************************************************************/
/* a[],b[]分别为数组,aLen,bLen表示数组长度 */
/************************************************************************/
void mergeArray(int a[],int aLen,int b[],int bLen)
{
//定义新数组的最大数组编号;
int len = aLen + bLen - 1;
//int * _a = new int[len];
aLen--;
bLen--;
while(aLen >= 0 && bLen >= 0)
{
if(a[aLen] > b[bLen])
a[len--] = a[aLen--];
else
a[len--] = b[bLen--];
}
while(aLen >= 0&& bLen < 0)
{
a[len--] = a[aLen--];
}
while(bLen >= 0&&aLen < 0)
{
a[len--] = b[bLen--];
}
}
int main(int argc,char * argv)
{
int a[20] = {1,3,4,5,6,7,8,9,11};
int b[] = {2,4,5,12,13};
//mergeArray(a,sizeof(a)/sizeof(a[0]),b,sizeof(b)/sizeof(b[0]));
mergeArray(a,9,b,5);
for(int i = 0 ; i < 14; i++)
{
cout<<a[i]<<" ";
}
getchar();
return 0;
}
运行结果:
二、合并两个单链表
分解:1、创建两个有序单链表;
2、得到正确的头结点;
3、结点之间比较,按顺序递推遍历完所有的结点,新建一个结点用来指向两个单链表里的准确结点;
链表结点结构:
/* struct Node */
struct Node{
int value;
Node(int _value = 0,Node* _next = NULL):value(_value),next(_next){}//构造函数;
Node * next;
};
/************************************************************************/
/* 单链表合并,head1和head2分别是两个单链表的头结点; */
/************************************************************************/
Node* mergeList(Node* head1,Node* head2)
{
if(head1 == NULL)
return head2;
if(head2 == NULL)
return head1;
//新建头结点;
Node* head = NULL;
if(head1->value < head2->value)
{
head = head1;
head1 = head1->next;
}
else
{
head = head2;
head2 =head2->next;
}
Node* p = head;
while(head1&&head2)
{
if(head1->value < head2->value)
{
p->next = head1;//未创建新结点,只是用next指针指向下一个结点;
head1 = head1->next;
}
else
{
p->next = head2;
head2 = head2->next;
}
p = p->next;
}
if(head1)
p->next = head1;
if(head2)
p->next = head2;
return head;
}
main函数部分:
/* 2、 链表合并 */
Node* head1 = new Node(1);//头结点1;
Node* cur = head1;
for(int i = 3 ; i < 10 ;i+=2)
{ //生成单链表1;
Node* p =new Node(i);
cur->next = p ;
cur = p;
}
Node* head2 = new Node(2);//头结点2
cur = head2;
for(int i = 4 ; i< 10 ; i+=2)
{ //生成单链表2;
Node* p = new Node(i);
cur->next = p ;
cur = p;
}
Node* head = mergeList(head1,head2);
while(head)
{
cout<<head->value<<" ";
head = head->next;
}
getchar();
return 0;
运行结果:
三、倒序打印一个单链表;
分解:既然是倒序打印,先打印最后一个。按照单链表的next指针可以直接找到最后一个结点,所以可以采用递归思想。
结点的结构如上题,函数代码如下:
/************************************************************************/
/* 采用递归思想倒序打印单链表,head是链表头结点; */
/************************************************************************/
void reversePrintNode(Node* head)
{
if(head)
{
reversePrintNode(head->next);
cout<<head->value<<" ";
}
}
main函数部分如下:
/* 倒序打印单链表 */
Node* head = new Node(1);
Node* cur = head;
for(int i = 2;i <= 10;i++)
{
Node* p = new Node(i);
cur->next = p;
cur = p;
}
reversePrintNode(head);
getchar();
return 0;
运行结果:
四、给定一个单链表的头指针和一个指定节点的指针,在O(1)时间内删除结点
分解:1、分别考虑删除点是头结点、尾结点和中间结点的情况
2、如果是尾结点与中间结点,如何根据头指针得到指定结点的指针;
当是头结点的时候,可以直接删除,此时头结点后不为空时,头结点的下一个结点将作为新的头结点;
当是尾结点的时候,通过头结点向后遍历查到的目标尾结点,此时直接删除即可,尾结点的前一个结点的next指针置NULL;
当是中间结点的时候,通过头结点向后遍历得到目标结点,记录目标结点的前一个结点和后一个结点,通过修改next指针的指向将2个结点连接,最后删除中间结点;
下面是代码部分:
/************************************************************************/
/* 给定头结点指针head,和指定删除的节点delNode */
/************************************************************************/
void deleteNode(Node* head,Node* delNode)
{
if(!head||!delNode)
return ;
if(delNode == head)//头结点
{
Node* p = head->next;
delete delNode;
delNode = NULL;
head = NULL;
return ;
}
else if(delNode->next!=NULL)//中间结点
{
Node* p = head;
Node* q = p->next;
while(q!=delNode&&q->next!=NULL)
{
p = q ;
q = q->next;
}
if(q = delNode && q->next!=NULL)
{
p->next = q->next;
delete delNode;
delNode = NULL;
return ;
}
}
else
{
Node* p =head;
while(p->next!=delNode)
{
p = p->next;
}
if(p->next == delNode)
{
delete delNode;
delNode = NULL;
p->next = NULL;
return;
}
}
}
五、找到链表倒数第K个节点
分解:假设单链表的长度为N,那么倒数第K个节点就是正数第N-K+1个节点;
思路:计算出单链表的长度,然后按顺序找到第N-K+1即可;
/************************************************************************/
/* 已知单链表头结点指针head,取倒数第K个 */
/************************************************************************/
Node* FindKthToTail(Node* head,unsigned int K)
{
if(!head||K == 0)
return;
int N = 0;
Node* p =head;
while(p!=NULL)
{
N++;
p = p->next;
}
//从前往后找到第N-K+1个节点;
p = head;//重置p;
for(int i = 1 ; i< N-K+1 ; i++)
{
p = p->next;
}
return p;
}
六、反转单链表
分解:假设原来的单链表是A>B>C,反转之后成为A<B<C,所以设A为Current节点,B为Next节点,反转之后指向改变
思路:先记录下A和B,然后把A与B之间的指向链接断开,Cur与Next指针分别往前移动,同时让A成为B的Next节点
Node* ReverseList(Node* head)
{
if(head == NULL)
return NULL;
Node* reverseHead = NULL;
Node* preNode = NULL;
Node* CurrentNode = head;
while(CurrentNode != NULL)
{
Node* nextNode = CurrentNode->next;//先记录下一个节点;
if(nextNode == NULL)
reverseHead = CurrentNode;
CurrentNode->next = preNode ; //让下一个结点指向前一个结点,改变指针的指向;
//设置下一个结点和前一个结点;
//按照题意,A>B转换成A<B,Current结点由A变成B,A由Current变成preNode,B由nextNode变成Current;
preNode = CurrentNode ;
CurrentNode = nextNode ;
}
return reverseHead;
}
七、二分查找
分解:二分查找是针对有序数组而言,有两个指针分别指向头和尾,根据头和尾取得mid值与查找目标比较,如果mid<val,则说明val值在mid值的右边,则min=mid+1;如果mid>val,则说明val值比mid值小,则max=mid-1;(以上假设数组是从小到大排序)
代码如下:
/************************************************************************/
/* 目标有序数组a,已知长度为len,查找目标为val */
/************************************************************************/
int binarySearch(int a[],int len,int val)
{
int minIndex = 0;
int maxIndex = len - 1;
int mid = -1;
while(maxIndex <= maxIndex)
{
mid = (minIndex + maxIndex)/2;
if(a[mid] == val)
return mid;
else if(a[mid] < val)
{
minIndex = mid + 1 ;
}
else
{
maxIndex = mid - 1;
}
}
return -1;
}