复习

合并:

这个比较简单,就大概的说下,先把两个序列合并,然后对序列进行len-1次相互元素的比较,即冒泡,最后得出一个有序序列
我觉得这种思想挺重要的,很多问题你可以用分治法去解决,但是中间过程步骤你可能先整体考虑,然后进行局部处理。

Node *Sort_Elem(Node *head)
{
	Node p;              //p变量主要是在冒泡里面做临时变量
	Node *q;
	int i=1,len;
	len=List_length(head);
	//cout<<len<<" ";
	q=new Node;
	q=head;
	//Out_list(p);
	p.data=0;
	p.next=NULL;
	cout<<head->next->data<<endl;
	while(true)                  //这里我用了冒泡排序,其他排序你们可以自己尝试下
	{                            
		while(head->next!=NULL)  //这里要从head->next开始判断,和普通的冒泡排序类似
		{
			if((head->data) > (head->next->data))
			{
				p.data=head->next->data;
				head->next->data=head->data;
				head->data=p.data;
			}
			head=head->next;
		}
		i++;
		if(i==len)  return q;  //循环跳出条件
		head=q;                //q主要是在一次冒泡过后,将头指针复位
	}
}


void Combine_list(Node *head1,Node *head2)
{
	Node *p;
	p=new Node;
	p=head1;          //先将头指针赋给p
	while(head1=head1->next)
	   if(head1->next==NULL)
	   {
		   head1->next=head2;
		   p=Sort_Elem(p);
		   Out_list(p);
		   return;
	   }	
}


栈:(记住头尾指针和栈长度)
栈这个东西,其实会用就行,毕竟STL里面有类模板,个人认为代码越简单越好,因为有些特殊的情况不是每个人都能考虑到的
用的多了,自然就会,所以把大致的思想理清楚就可以了。
下面是精简了很多的代码,基本上是主要内容都有了。

 

void Init_stack(Stack &S)
{
	S.base = new int[Max];
	S.top = S.base;
	S.length = Max;
}
void Push(Stack &S,int e)  
{
	if(S.top - S.base == S.length)
	{
		printf("栈已满!\n");
		return;
	}
	*S.top = e;
	S.top++;
}

void Pop(Stack &S,int &e)   //STL里面的stack出栈只是Pop(); 后面一个参数作用不大
{
	if(S.top == S.base)
		printf("栈已空\n");
	S.top--;
	e = *S.top;
}

int Gettop(Stack &S)
{
	if(S.top == S.base)
		printf("栈已空!\n");
	return (*(S.top-1));
}

int Stack_length(Stack &S)
{
	Stack flag;
	flag.top = S.top;
	int k=0;
	while(flag.top--)
	{
		k++;
		if(flag.top == S.base)
			return k;
	}
}

void Out_stack(Stack &S)
{
	Stack flag;
	flag.top = S.top;
	while(flag.top--)
	{
		printf("%d ",*flag.top);
		if(flag.top == S.base)
		{
			printf("\n");
			return;
		}
	}
}


 

进制转换的函数:
这个希望都能记住,因为这种取模求余的思想在很多题目上都会有体现,像大数问题,某些字符串问题和欧几里德类的问题。

void change(Stack S,int a,int b)
{
	int s=0,c,k;
	k=a;
	while(a)
	{
		Push(S,a%b);
		a/=b;
	}
	while(S.base != S.top)
	{
		s += Gettop(S);
		s *= 10;
		Pop(S,c);
	}
	cout<<"十进制数 "<<k<<" 转换为 "<<b<<" 进制数为: "<<s/10<<endl;
}


括号匹配源代码:
括号匹配只是栈里面的一个简单的运用,帮助你理解栈的实质思想吧,自我感觉没什么技巧可言

 

void Kuo_hao(Stack &S)
{
	char c[101];
	int flag = 1,i,e;
	cin>>c;          //读入数据
	for(i=0;c[i]!='\0';i++)
	{
		if(c[i] == '(' || c[i] == '[')
			Push(S,(int)c[i]);       //压栈
		if(c[i] == ')')              //如果匹配,弹出,标记,break用不用无所谓
		{
			if( (char)Gettop(S) == '(' )
				Pop(S,e);
			else
				flag = 0;
		}
		if(c[i] == ']')
		{	
			if( (char)Gettop(S) == '[' )
				Pop(S,e);
			else
				flag = 0;
		}
	}
	if(S.top == S.base && flag)
		cout<<"所输入的括号匹配成功!"<<endl;
	else
		cout<<"所输入的括号匹配失败!"<<endl;
}


 

//这里的链式队列步骤基本是按照书本上的,可以自己尝试不加头结点,如何构造链式队列,并且基本操作可以执行

这里的链式队列操作无非就是创建,销毁,增加(减少),查找,更新这些操作
所以你基本记住一个头指针和一个尾指针,剩下的就是移动这些指针来操作,中间步骤无非就是临时创建一个指针或者一个存储单位
有些时候,你要先想下如果插入是否会溢出,主函数传递过来的能不能在调用的函数里面进行操作,头指针和尾指针什么时候相遇。。。
大概就是这些内容

void Init_queue(LinkQueue &Q)
{ 
	Q.front=Q.rear=new QNode;
	Q.front->next=NULL; // 头结点的next域为空
}

void Destroy_queue(LinkQueue &Q)
{ 
	while(Q.front) // Q.front不为空
	{ 
		Q.rear=Q.front->next; // Q.rear指向Q.front的下一个结点
		delete Q.front; // 释放Q.front所指结点
		Q.front=Q.rear; // Q.front指向Q.front的下一个结点
	}
}

bool Queue_empty(LinkQueue Q)
{ 
	if(Q.front->next==NULL)
		return true;
	else
		return false;
	//return !(Q.front->next);  精简
}

int Queue_length(LinkQueue Q)
{ 
	int i=0; 
	QueuePtr p=Q.front; // 临时指针p指向头结点
	while(Q.rear!=p)
	{ 
		i++; 
		p=p->next; // p指向下一个结点
	}
	return i;
}

int Get_head(LinkQueue Q,QElemType &e)
{ 
	QueuePtr p;
	if(Q.front==Q.rear) 
		return 0;
	p=Q.front->next; 
	e=p->data;
	return 1;
}

void En_queue(LinkQueue &Q,QElemType e)
{
	QueuePtr p;
	p=new QNode; // 动态生成新结点
	if(!p)
		exit(1); 
	p->data=e;
	p->next=NULL; 
	Q.rear->next=p; // 原队尾结点的指针指向新结点
	Q.rear=p; // 尾指针指向新结点
}

int De_queue(LinkQueue &Q,QElemType &e)
{ 
	QueuePtr p;
	if(Q.front==Q.rear) 
		return 0;
	p=Q.front->next; // p指向队头结点
	e=p->data; 
	Q.front->next=p->next; // 头结点指向下一个结点
	if(Q.rear==p) // 删除的是队尾结点
		Q.rear=Q.front; // 修改队尾指针指向头结点(空队列)
	delete p; 
	return 1;
}

void Queue_traverse(LinkQueue Q,void(*visit)(QElemType)) //从队头到队尾依次对队列Q中每个元素调用函数visit()
{ 
	QueuePtr p;
	p=Q.front->next; // p指向队头结点
	while(p) // p指向结点
	{ 
		visit(p->data); // 对p所指元素调用visit()
		p=p->next; // p指向下一个结点
	}
	printf("\n");
}


 

下面的是二叉树的构建,遍历,计数,复制的基本操作
二叉树,首先你要想到,它要有左右孩子,所以这个时候,你要选择递归的方式来解决问题
上面的这些操作都用到了递归,构建无非就是开辟一个节点,然后左右递归,遍历类似
计数和复制  你要先判断树有没有构建,然后进行操作
关于递归的技巧  多敲敲就会了

 

BiTNode *CreateBiTree(){
    char ch;
    BiTNode *T;
    scanf("%c",&ch);
    if(ch=='#')T=NULL;
    else{
        T = new BiTNode;
        T->data = ch;
        T->lchild = CreateBiTree();
        T->rchild = CreateBiTree();
    }
    return T;//返回根节点
}

int Depth(BiTNode *T)
{
	if(T == NULL) return 0;
	else
		return Depth(T->lchild)>Depth(T->rchild)?Depth(T->lchild)+1:Depth(T->rchild)+1;
}

int NodeCount(BiTNode *T,int &Yezi,int &flag)
{
	
	if(T == NULL)
		return 0;
	else
	{
		if(T->lchild == NULL && T->rchild == NULL) Yezi++;
		if(T->lchild != NULL && T->rchild != NULL) flag++;
		return NodeCount(T->lchild,Yezi,flag) + NodeCount(T->rchild,Yezi,flag) + 1;
	}
}
//先序遍历二叉树
void PreOrderTraverse(BiTNode *T){
    if(T){
		printf("%c",T->data);
		PreOrderTraverse(T->lchild);
		PreOrderTraverse(T->rchild);
    }
}

//中序遍历
void InOrderTraverse(BiTNode *T){
    if(T){
		PreOrderTraverse(T->lchild);
		printf("%c",T->data);
		PreOrderTraverse(T->rchild);
    }
}
//后序遍历
void PostOrderTraverse(BiTNode *T){
    if(T){
		PreOrderTraverse(T->lchild);
		PreOrderTraverse(T->rchild);
		printf("%c",T->data);
    }
}

void Copy(BiTNode *T,BiTNode *(&TT))
//  囧(/ □ \),这个地方指针问题调试了好久,各种情况都试了一下,最后终于OK了!
{

	
	if(T == NULL)
	{
		TT = NULL;
		return;
	}
	else
	{
		TT = new BiTNode;

		TT->data = T->data;
		Copy(T->lchild,TT->lchild);
		Copy(T->rchild,TT->rchild);
	}

}


顺序查找 没什么说的,遍历就行
二分查找里面,你要知道的就是一个low,一个high下标
因为你每次都是二分,直到不能再分为止,所以一个while循环,里面就是结束的临界点
然后while循环里面你要操作,这个时候你就判断如果找到了,直接跳出。

int Search_Seq(SSTable ST,int x,int &k)
{
	int i;
	for(i = 1; i <= ST.length; i++,k++)
	{
		if(ST.R[i].key == x)
			return i;
	}
	return -1;
}

int Search_Bin(SSTable ST,int x,int &k)
{
	int i;
	int low,high;
	low = 1; high = ST.length;
	while(low<=high)
	{
		k++;
		int mid = (low+high)/2;
		if(ST.R[mid].key == x)
			return mid;
		else if(ST.R[mid].key < x)
			low = mid + 1;
		else
			high = mid - 1;
	}
	return -1;
}


 

下面的就是图了
图里面有很多算法,dfs和bfs是比较简单基础的
那么怎么来记呢
dfs就是创建好了一个邻接矩阵后,对里面的元素先for循环遍历,对于每遍历一个元素
此时你要标记它访问过,然后再访问和这个元素有关的其他元素,并且其他元素也是没有标记的
这里就有点像栈的形式,不断向下搜索
void DFS(AMGraph &G,int k)
{
    int j;
    visited[k]=true;
    cout<<G.vexs[k]<<" ";
    for(j=0;j<G.vexnum;j++)
    {
        if(!visited[j]&&G.arcs[k][j]!=MaxInt)
            DFS(G,j);
    }
}


而对于bfs来说,就类似于先找出一个点,然后把与这个点有关的所有点都遍历完
全部存放到队列里面,所以while循环里面你要先从队列里面弹出一个元素,进行操作,这个操作就会把所有有关的点全部压入队列
所以不断重复操作,直到队列非空
大概思路就是这样的
和bfd有关的题目主要是迷宫之类的

 

void BFS(ALGraph &G,char v)
{

	cout<<v<<" ";  visited[v]=true;
	char flag,k;
	queue<char>q;
	q.push(v);
	while(!q.empty())
	{
		flag=q.front();//cout<<flag;
		q.pop();
		ArcNode *pp;
		pp = new ArcNode;
		pp=G.vertices[LocateVex(G,flag)].firstarc;

		//cout<<pp->adjvex<<endl;
		//k=G.vertices[pp->adjvex];
		for(;pp!=NULL;pp=pp->nextarc)
		{
			k=G.vertices[pp->adjvex].data;
			//cout<<visited[k];
			if(!visited[k])
			{
				cout<<k<<" ";
				//cout<<q.empty();
				visited[k]=true;
				q.push(k);
			}
		}
	}//cout<<"nihao";

}


二叉排序树:
主要是构建,查找,插入,删除操作
构建这里就是不断调用插入函数来实现,while循环建议用9999999这种大数形式
因为书上给的伪代码在数据类型上不同,所以导致用#这种会错
然后是插入函数里面无非就是递归插入(因为二叉树嘛!),在查找函数上,也主要是递归形式吧
删除函数上面,因为要删的是参数的节点,所以你首先要查找到这个节点,定位好后,你要根据中序遍历的结果
删除相应的节点,并且保证操作后的中序序列仍能保持原来的序(貌似老师上课是这样说的),不过我觉的你按照代码的步骤
在纸上画画,大概也就是删节点,孩子节点替代。。

BSTree SearchBST(BSTree T,int key)
{
	if(!T || key == T-> data.key){
		//cout<<1;
		return T;}
	else if(key < T-> data.key)
		return SearchBST(T-> lchild,key);
	else
		return SearchBST(T-> rchild,key);
}

void InsertBST(BSTree &T,ElemType E)
{
	if(!T)        //这个地方不能把if的顺序放到后面,我调试了下,貌似是优先判断是否为空,然后在操作......
	{
		BSTree s;
		s = new BSTNode;
		s ->data = E;
		s -> lchild = s -> rchild = NULL;
		T = s;
	}
	else if(E.key < T-> data.key)
		InsertBST(T-> lchild,E);
	else if(E.key > T-> data.key)
		InsertBST(T-> rchild,E);
}

void CreatBST(BSTree &T)
{
	ElemType e;
	T = NULL;
	cin>>e.key;
	while(e.key<999999)
	{
		InsertBST(T,e);
		cin>>e.key;
	}
}

void DeleteBST(BSTree &T,int key)//delete函数没有调试,书上代码全都给出来了
{
	BSTree f=NULL,p=T,s,q;

	while(p)
	{
		if(p->data.key == key)
			break;
		else if(p->data.key>key)
			p = p -> lchild;
		else
			p = p -> rchild;
	}

	if(!p)  return;

	if(p -> lchild && p -> rchild)
	{
		q = p;
		s = p -> lchild;
		while(p -> lchild)
		{
			q = s;
			s = s -> rchild;
		}
		if(q != p)      //这个地方按照书上给的那个图,可能会产生疑惑
			//书上给出的只是中序遍历后节点刚好是右子树的,还有一种就是没有右子树的情况......
			q -> rchild = s -> rchild;
		else
			q -> lchild = s -> lchild;
		delete s;
		return;
	}
		else if(!p -> rchild)
		{
			q = p;
			p = p ->lchild;
		}
		else if(!p ->lchild)
		{
			q = p;
			p = p -> rchild;
		}
		if(!f) 
			T = p;
		else if(q == f ->lchild)
			f ->lchild = p;
		else 
			f ->rchild = p;
		delete q;
	
}


 

后面的四种排序是最近讲的,这里就不提了
原理自己看看就明白

后面我推荐一片文章:数据结构心得

链接
http://blog.csdn.net/k183000860/article/details/42101783

 

posted @ 2014-12-23 17:34  __夜风  阅读(178)  评论(0编辑  收藏  举报