顺序存储结构和链式存储结构的优缺点比较,以及使用情况。
优缺点
顺序存储时,相邻数据元素的存放地址也相邻(逻辑与物理统一);要求内存中可用存储单元的地址必须是连续的。
优点:存储空间利用率高。缺点:插入或删除元素时不方便。
链式存储时,相邻数据元素可随意存放,但所占存储空间分两部分,一部分存放结点值,另一部分存放表示结点间关系的指针
优点:插入或删除元素时很方便,使用灵活。缺点:存储空间利用率低。
使用情况
顺序表适宜于做查找这样的静态操作;链表宜于做插入、删除这样的动态操作。
若线性表的长度变化不大,且其主要操作是查找,则采用顺序表;
若线性表的长度变化较大,且其主要操作是插入、删除操作,则采用链表。
比较
顺序表的存储空间是静态分配的
链表的存储空间是动态分配的
顺序表可以随机存取,也可以顺序存取
链表是顺序存取的
插入/删除时移动元素个数
顺序表平均需要移动近一半元素
链表不需要移动元素,只需要修改指针
链式二叉树的相关操作
头文件
#pragma once
// 二叉树的链式存储方式---孩子表示法
typedef char BTDataType;
typedef struct BTNode
{
struct BTNode* _pLeft;
struct BTNode* _pRight;
BTDataType _data;
}BTNode;
BTNode* CreateBinTree(BTDataType* array, int size, BTDataType invalid);
BTNode* CopyBinTree(BTNode* pRoot);
void PreOrder(BTNode* pRoot);
void InOrder(BTNode* pRoot);
void PostOrder(BTNode* pRoot);
void LevelOrder(BTNode* pRoot);
int GetBinTreeSize(BTNode* pRoot);
int GetKLevelNodeCount(BTNode* pRoot, int K);
int GetLeafCount(BTNode* pRoot);
int GetBinTreeHeight(BTNode* pRoot);
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
void MirrorNor(BTNode* pRoot);
void Mirror(BTNode* pRoot);
void DestroyBinTree(BTNode** pRoot);
void TestBinTree();
//申请内存空间
BTNode* BuyBinTeeNode(BTDataType data)
{
BTNode* pNewNode = (BTNode*)malloc(sizeof(BTNode));
if (NULL == pNewNode)
{
assert(0);
return NULL;
}
pNewNode->_data = data;
pNewNode->_pLeft = NULL;
pNewNode->_pRight = NULL;
return pNewNode;
}
// 二叉树的创建
BTNode* _CreateBinTree(BTDataType* array, int size, int* index, BTDataType invalid)
{
BTNode* pRoot = NULL;
if (*index < size && invalid != array[*index])
{
// 根节点
pRoot = BuyBinTeeNode(array[*index]);
// 根的左子树
++(*index);
pRoot->_pLeft = _CreateBinTree(array, size, index, invalid);
// 根的右子树
++(*index);
pRoot->_pRight = _CreateBinTree(array, size, index, invalid);
}
return pRoot;
}
//前序遍历
void MirrorNor(BTNode* pRoot)
{
Queue q;
if (NULL == pRoot)
return;
QueueInit(&q);
QueuePush(&q, pRoot);
while (!QueueEmpty(&q))
{
BTNode* pCur = QueueFront(&q);
Swap(&pCur->_pLeft, &pCur->_pRight);
// 如果左孩子存在,保存当前节点的左孩子
if (pCur->_pLeft)
QueuePush(&q, pCur->_pLeft);
// 如果右孩子存在,保存当前节点的右孩子
if (pCur->_pRight)
QueuePush(&q, pCur->_pRight);
QueuePop(&q);
}
QueueDestroy(&q);
}
// 中序遍历
void PreOrder(BTNode* pRoot)
{
if (pRoot)
{
printf("%c ", pRoot->_data);
PreOrder(pRoot->_pLeft);
PreOrder(pRoot->_pRight);
}
}
// 层序遍历
void LevelOrder(BTNode* pRoot)
{
Queue q;
if (NULL == pRoot)
return;
QueueInit(&q);
QueuePush(&q, pRoot);
while (!QueueEmpty(&q))
{
BTNode* pCur = QueueFront(&q);
printf("%c ", pCur->_data);
// 如果左孩子存在,保存当前节点的左孩子
if (pCur->_pLeft)
QueuePush(&q, pCur->_pLeft);
// 如果右孩子存在,保存当前节点的右孩子
if (pCur->_pRight)
QueuePush(&q, pCur->_pRight);
QueuePop(&q);
}
QueueDestroy(&q);
printf("\n");
}
// 后序遍历
void PostOrder(BTNode* pRoot)
{
if (pRoot)
{
PostOrder(pRoot->_pLeft);
PostOrder(pRoot->_pRight);
printf("%c ", pRoot->_data);
}
}
//交换节点
void Swap(BTNode** pLeft, BTNode** pRight)
{
BTNode* pTemp = *pLeft;
*pLeft = *pRight;
*pRight = pTemp;
}
//交换节点
void Swap(BTNode** pLeft, BTNode** pRight)
{
BTNode* pTemp = *pLeft;
*pLeft = *pRight;
*pRight = pTemp;
}
BTNode* CreateBinTree(BTDataType* array, int size, BTDataType invalid)
{
int index = 0;
return _CreateBinTree(array, size, &index, invalid);
}
//确定叶子结点个数
int GetLeafCount(BTNode* pRoot)
{
if (NULL == pRoot)
return 0;
if (NULL == pRoot->_pLeft && NULL == pRoot->_pRight)
return 1;
return GetLeafCount(pRoot->_pLeft) + GetLeafCount(pRoot->_pRight);
}
// 获取二叉树中第K层节点个数
int GetKLevelNodeCount(BTNode* pRoot, int K)
{
if (NULL == pRoot || K <= 0)
return 0;
if (1 == K)
return 1;
return GetKLevelNodeCount(pRoot->_pLeft, K - 1) +
GetKLevelNodeCount(pRoot->_pRight, K - 1);
}
// 检测值为x的元素是否在二叉树中,在返回该节点的地址,否则返回NULL
BTNode* BinaryTreeFind(BTNode* pRoot, BTDataType x)
{
BTNode* pRet = NULL;
if (NULL == pRoot)
return NULL;
if (x == pRoot->_data)
return pRoot;
if (pRet = BinaryTreeFind(pRoot->_pLeft, x))
return pRet;
return BinaryTreeFind(pRoot->_pRight, x);
}
//销毁二叉树
void DestroyBinTree(BTNode** pRoot)
{
assert(pRoot);
if (*pRoot)
{
DestroyBinTree(&(*pRoot)->_pLeft);
DestroyBinTree(&(*pRoot)->_pRight);
free(*pRoot);
*pRoot = NULL;
}
}