Linux与数据结构 2019-3-10 下午

1.栈与队列

1.1 如何使用两个栈实现队列先进先出的功能

1.定义一个结构体,该结构体中包含两个栈的指针和一个用来表示当前队列长度的int型变量;

#include<stdio.h>
#include<stdlib.h>

typedef struct node
{
	int nValue;
	struct node *pNext;
}Node;

typedef struct stack
{
	Node *pTop;
	int nCount;
}Stack;

typedef struct queue
{
	Stack *pStack1;
	Stack *pStack2;
	int qCount
}Queue;

void s_Init(Stack **pStack)
{
	*pStack = (Stack*)malloc(sizeof(Stack));
	(*pStack)->pTop = NULL;
	(*pStack)->nCount = 0;
}

void s_Push(Stack *pStack,int nNum)
{
	if(pStack == NULL)
	{
		printf("栈不存在\n");
		return;
	}

	Node *pTemp = NULL;
	pTemp = (Node*)malloc(sizeof(Node));
	pTemp->nValue = nNum;
	pTemp->pNext = pStack->pTop;
	pStack->pTop = pTemp;
	pStack->nCount++;
}

int s_Pop(Stack *pStack)
{
	if(pStack == NULL || pStack->nCount == 0)
	{
		printf("错误\n");
		return -1;
	}

	int nNum;
	Node *pDel = NULL;
	pDel = pStack->pTop;
	nNum = pDel->nValue;

	pStack->pTop = pStack->pTop->pNext;
	
	free(pDel);
	pDel = NULL;

	pStack->nCount--;
	return nNum;
}

void s_Clear(Stack *pStack)
{
	if(pStack == NULL)return;

	while(pStack->nCount != 0)
	{
		s_Pop(pStack);
	}
}

void s_Destroy(Stack **pStack)
{
	s_Clear(*pStack);

	free(*pStack);
	*pStack = NULL;
}

Node *s_GetTop(Stack *pStack)
{
	if(pStack == NULL)exit(1);

	return pStack->pTop;
}

int s_GetCount(Stack *pStack)
{
	if(pStack == NULL)exit(1);

	return pStack->nCount;
}

int s_IsEmpty(Stack *pStack)
{
	if(pStack == NULL)exit(1);

	return pStack->nCount == 0 ?1:0;
}

//--------------------两个栈实现队列的功能---------------------------
void q_Init(Queue **pQueue)
{
	*pQueue = (Queue*)malloc(sizeof(Queue));
	(*pQueue)->pStack1 = NULL;
	(*pQueue)->pStack2 = NULL;
	(*pQueue)->qCount = 0;
	
	s_Init(&((*pQueue)->pStack1));
	s_Init(&((*pQueue)->pStack2));
}

void q_Push(Queue *pQueue,int nNum)
{
	if(pQueue == NULL || pQueue->pStack1 == NULL || pQueue->pStack2 == NULL)return;

	//栈1入队
	//栈2 内若有元素 则将其放回栈1 
	while(pQueue->pStack2->nCount != 0)
	{
		s_Push(pQueue->pStack1,s_Pop(pQueue->pStack2));
	}

	//新来的元素入栈1
	s_Push(pQueue->pStack1,nNum);

	(*pQueue)->qCount++;
}

int q_Pop(Queue *pQueue)
{
	if(pQueue == NULL || pQueue->pStack1 == NULL || pQueue->pStack2 == NULL || 
		(pQueue->pStack1->nCount == 0 && pQueue->pStack2->nCount == 0))return -1;
	
	//栈2 出队
	//栈1有元素 则将元素依次放入栈2 
	while(pQueue->pStack1->nCount != 0)
	{
		s_Push(pQueue->pStack2,s_Pop(pQueue->pStack1));
	}

	int nNum;
	nNum = s_Pop(pQueue->pStack2);

	(*pQueue)->qCount--;

	return nNum;
}


int main()
{
	Queue *pQueue = NULL;

	q_Init(&pQueue);
	q_Push(pQueue,1);
	q_Push(pQueue,2);
	q_Push(pQueue,3);
	q_Push(pQueue,4);

	printf("%d\n",q_Pop(pQueue));
	printf("%d\n",q_Pop(pQueue));
	printf("%d\n",q_Pop(pQueue));
	return 0;
}

2.我的思路是:用栈1来正着存放数组(先进去的元素在栈底部,后进去的在栈顶部),用栈2来存放反着的元素(先进去的元素在栈顶部,后进去的在栈底部),这样的话当我们要出栈时只用pop以下栈2即可达到目的;

1.2 如何使用两个队列来实现栈的内容

1.定义一个结构体,其中包括两个队列指针和一个int型变量;

#include<stdio.h>
#include<stdlib.h>

typedef struct node
{
	int nValue;
	struct node *pNext;
}Node;

typedef struct queue
{
	int nCount;
	Node *pHead;
	Node *pTail;
}Queue;

typedef struct stack
{
	Queue *pQueue1;
	Queue *pQueue2;
	int nCount;
}Stack;

void q_Init(Queue **pQueue)
{
	*pQueue = (Queue*)malloc(sizeof(Queue));
	(*pQueue)->nCount = 0;
	(*pQueue)->pHead = NULL;
	(*pQueue)->pTail = NULL;
}

void q_Push(Queue *pQueue,int nNum)
{
	if(pQueue == NULL)return;

	Node *pTemp = NULL;
	pTemp = (Node*)malloc(sizeof(Node));
	pTemp->nValue = nNum;
	pTemp->pNext = NULL;

	//尾添加
	if(pQueue->pHead == NULL)
	{
		pQueue->pHead = pTemp;
	}
	else
	{
		pQueue->pTail->pNext = pTemp;
	}
	pQueue->pTail = pTemp;
	pQueue->nCount++;
}

int q_Pop(Queue *pQueue)
{
	if(pQueue == NULL || pQueue->nCount == 0)return -1;

	int nNum;
	Node *pDel = NULL;
	pDel = pQueue->pHead;
	nNum = pDel->nValue;

	pQueue->pHead = pQueue->pHead->pNext;

	free(pDel);
	pDel = NULL;

	pQueue->nCount--;

	if(pQueue->nCount == 0)
	{
		pQueue->pTail = NULL;
	}

	return nNum;
}

int q_IsEmpty(Queue *pQueue)
{
	if(pQueue== NULL)exit(1);

	return pQueue->nCount == 0?1:0;
}

//----------------------------------
void s_Init(Stack **pStack)
{
	*pStack = (Stack*)malloc(sizeof(Stack));
	(*pStack)->nCount = 0;
	(*pStack)->pQueue1 = NULL;
	(*pStack)->pQueue2 = NULL;

	q_Init(&((*pStack)->pQueue1));
	q_Init(&((*pStack)->pQueue2));
}

void s_Push(Stack *pStack,int nNum)
{
	if(pStack == NULL || pStack->pQueue1 == NULL || pStack->pQueue2 == NULL)return;

	if(pStack->pQueue1->nCount != 0)
	{
		q_Push(pStack->pQueue1,nNum);
	}
	else
	{
		q_Push(pStack->pQueue2,nNum);
	}

	pStack->nCount++;
}

int s_Pop(Stack *pStack)
{
	if(pStack == NULL || pStack->pQueue1 == NULL || pStack->pQueue2 == NULL || pStack->nCount == 0)return -1;
	
	int nNum;
	if(!q_IsEmpty(pStack->pQueue1))
	{
		//队列1的元素依次压入队2
		while(pStack->pQueue1->nCount > 1)
		{
			q_Push(pStack->pQueue2,q_Pop(pStack->pQueue1));
		}
		nNum = q_Pop(pStack->pQueue1);
	}
	else
	{
		while(pStack->pQueue2->nCount > 1)
		{
			q_Push(pStack->pQueue1,q_Pop(pStack->pQueue2));
		}

		nNum = q_Pop(pStack->pQueue2);
	}

	pStack->nCount--;
	return nNum;
}



int main()
{
	Stack *pStack = NULL;
	s_Init(&pStack);

	s_Push(pStack,1);
	s_Push(pStack,2);
	s_Push(pStack,3);
	s_Push(pStack,4);

	printf("%d\n",s_Pop(pStack));
	printf("%d\n",s_Pop(pStack));
	printf("%d\n",s_Pop(pStack));

	return 0;
}

2.这里我的思路是:在push的时候queue1与queue2中必有一个是空的,那么我将新压入的元素放到非空的队列的尾部;在pop过程中,我们找出不为空的队列,将该队列除了尾部的元素以外的所有元素压入到空的队列中,在将只剩尾部的队列pop掉,作为返回值返回;

2.树

2.1 树,也成树状图,是由n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

2.2 一棵树必然包括:根节点、叶子节点、中间节点、边、路径(是指从根节点到叶子节点的路径)、树的层数(从1开始)、树的高度(也就是树的层数)、某个节点的高度(表示以改节点为根节点的树的层数)、深度

2.3 一棵树可能包括:权值、带权节点

2.4 二叉树

1.每个节点最多只含有两个孩子节点;
2.子树、左子树、右子树
3.度:父节点孩子的个数

2.5 特殊的二叉树

1.满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树;
2.完全二叉树:对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树(或者说当只有最后一层有空缺,并且从右向左空缺的树);
3.排序二叉树(二叉搜索树)BST:所有左子树的元素都比父节点小,所有右子树的元素都比父节点大,且其中每个节点都是唯一存在的,没有相同的值;
4.平衡二叉树(AVL树):必须以是一颗BST为前提条件,树中任意节点左右子树的高度差不超过1;
5.B-Tree(B树):是一个节点可以拥有多于2个子节点的二叉查找树;
1).根节点至少有两个子节点;
2).每个节点有M-1个key,并且以升序排列;
3).位于M-1和M key的子节点的值位于M-1 和M key对应的Value之间;
4).其它节点至少有M/2个子节点;
6.B+树:B+树是对B树的一种变形树,它与B树的差异在于:
1).有k个子结点的结点必然有k个关键码;
2).非叶结点仅具有索引作用,跟记录有关的信息均存放在叶结点中;
3).树的所有叶结点构成一个有序链表,可以按照关键码排序的次序遍历全部记录;

2.6 二叉树的性质

1.一个K层的二叉树,最多有二的K次方减1个节点(k>=1);
2.一个K层的二叉树最多有二的K减一次方个节点;
3.n0是度为0的节点的个数,n1是度为1的节点的个数,n2是度为2的节点的个数,总结点的个数S=n0+n1+n2,S=2*n2+n1,由此可得n0=n2+1;
4.一个有n个节点的完全二叉树,其高度为log以二为底的n并向下取整再加1;
5.把一颗完全二叉树按照从上到下从左到右的顺序从1开始进行编号,其中编号为i的节点若满足2i<=n,则说明该节点有左孩子,并且左孩子的编号为2i<=n;若满足2i+1<=n,则说明该节点有右孩子,并且右孩子的编号为2i+1<=n;
6.对于完全二叉树,父节点的编号范围为: 1~n/2 ;
7.从0开始编号的完全二叉树,编号为i的节点的左孩子编号为2i+1,右孩子编号为2i+2,父节点的编号范围为0~n/2+1。

猜你喜欢

转载自blog.csdn.net/weixin_42896619/article/details/88431055
今日推荐