C++常用算法(上)

关于算法,在这里给出我们常用的几个算法:

◆合并排序,将两个已经排序的数组合并成一个数组,其中一个数组能容下两个数组的所有元素;

◆合并两个单链表;

◆倒序打印一个单链表;

◆给定一个单链表的头指针和一个指定节点的指针,在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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值