day1
顺序表:
1.逻辑结构:按顺序进行存储,内存中连续且大小固定
逻辑结构:除了首尾,中间的元素,有且只有一个一个前驱与后继。
特点:顺序并连续存储
大小固定,提前申请好内存的空间
表满不能存,表空不能删
访问和查找比较方便
插入和删除不太方便,需要移动元素
int insertList(List *pList,int pos,data_type item)
{
//入参判断
if(NULL == pList)
{
return MALLOCERROR;
}
//合法位置判断
if(pos < 0 || pos > pList->count)
{
return POSERROR;
}
//判断表是否满
if(pList->count == N)
{
return LISTFULL;
}
for(int i = pList->count-1;i >= pos;i--)
{
pList->arr[i+1] = pList->arr[i];//数据元素的移动
}
pList->arr[pos] = item;
pList->count++;
return OK;
}
int deleteItemList(List *pLsit,int pos,data_type *pData)
{
if(pList == NULL)
{
return MALLOCERROR;
}
if(pos < 0 || pos > count-1)
{
return LISTEMPTY;
}
*pData = pList->arr[pos];
for(int i = pos;i >= pLIst->count-1;i++)\
{
pList->arr[i] = pList->arr[i+1];
}
return OK;
}
int destoryList(List **ppList)
{
if((*ppList == NULL) || (ppList == NULL))
{
return MALLOCERROR;
}
free(*ppList);
*ppList = NULL;
return OK;
}
day2
单链表
节点data存放数据元素,而next是一个指针,指向后继节点(地址)
头节点:第一个数据域无效的节点
首节点:第一个数据域有效节点
尾节点:指针域为空的节点
int insertItemLink(linkNode *pHead,in pos,data_type item)
{
if(NULL == pHead)
{
return LINKNULL;
}
linkNode *pNew = NULL;
pNew = (linkNode *)malloc(sizeof(linkNode));
if(NULL == pNew)
{
perror("malloc error");
return MALLOCERROR;
}
memeset(pNew,0,sizeof(linkNode));
pNew->data = item;
linkNode *pt = NULL;
pt = pHead;
switch(pos)
{
case HEAD:
pNew->next = pHead->next;
pHead->next = pNew;
break;
case TAIL:
while(pt->next != NULL)
{
pt = pt->next;
}
pt->next = pNew;
break;
default:
for(int i = 1;i <= pos-1;i++)
{
if(NULL == pt)
{
free(pNew);
PNew = NULL;
return POSERROR;
}
pt = pt->next; //游标移动到要插入位置的前一个位置停下
}
//先对pNew的指针域进行赋值,保护好要插入节点后面的节点地址
pNew->next = pt->next;
pt->next = pNew;
}
}
int deleteItenLink(linkNode *pHead,int pos,data_type *pData)
{
if(NULL == pHead)
{
return LINKNULL;
}
linkNode *pd = NULL;
linkNode *pt = NULL;
pd = pHead->next; //指向首节点
pt = pHead; //指向头节点
switch(pos)
{
case HEAD:
*pData = pd->data;
pHead->next = pd->next;
free(pd);
pd = NULL;
break;
case TAIL:
while(pd->next != NULL)
{
pt = pd;
pd = pd->next;
}
*pData = pd->data;
pt->next = NULL;
free(pd);
pd = NULL;
break;
default:
//pd指向要删除的节点本身
//pt指向要删除节点的前一个节点
for(int i = 1;i <= pos+1;i++)
{
pt = pd;
pd = pd->next;
}
*pData = pd->data;
pt->next = pd->next;
free(pd);
pd = NULL;
}
return OK;
}
int destoryLinkNode(linkNode *ppHead)
//*ppHead------->pHead ppHead------->&pHead
{
if((NULL == ppHead) || (NULL == *ppHead))
{
perror("malloc error");
return LINKNULL;
}
while(1)
{
linkNode *pd = NULL;
pd = (*ppHead)->next;
if(NULL == pd)
{
break;
}
(*ppHead)->next = pd->next;
free(pd);
pd = NULL;
}
free(*ppHead);
*ppHead = NULL;
return OK;
}
day3
int reverse(linkNode *pHead)
{
if(NULL == pHead)
{
return LINKNULL;
}
//先把原来的链表剪断
//L1:带头节点的空链表
//L2:不带头节点的链表
linkNode *pFirst = NULL;
pFirst = pHead->next;
pHead->next = NULL;
linkNode *pNew = NULL;//y用于指向要插入的节点地址
//将L2中的节点头部插入到L1中
while(1)
{
pNew = pFirst;
if(NULL == pNew)
{
break;
}
pFirst = pFirst->next;
//头部插入
pNew->next = pHead->next;
pHead->next= pNew;
}
return OK;
}
双链表
struct dbLinkNode *pre;
struct dbLinkNode *next;
插入
pNew->data = item;
dbLinkNode *pTemp = NULL;
pTemp = pHead;
//头插
pNew->pre = pHead;
pNew->next = pHead->next;
if(NULL != pHead->next)
{
pHead->next = pNew;
}
pHead->next = pNew;
//尾插
//中间插入
for(int i = 0;i <= pos-1;i++)
{
pTemp = pTemp->next;
}
//先保护好要插入的节点后面的节点
·pNew->next = pTemp->next;
pNew->pre = pTemp;
if(pTemp->next != NULL)
{
pTemp->next->pre = pNew;
}
pTemp->next = pNew;
栈:限制在一段进行插入和删除的线性表(先进后出)
顺序栈 链式栈
操作的话只能在栈顶操作
入栈:增加元素 出栈:删除元素
经典面试题:
顺序栈:
typedef struct stack
{
data_type arr[N]; //顺序且连续,大小固定
int top; //定义栈顶元素下标,top == -1 栈空 top == N 栈满
}Stack;
链式栈:插入操作和删除操作均在链表头部进行,链表尾部就是栈底,栈顶指针就是头指针。
day4
队列:先进先出、只允许在队尾插入,队头删除。
typedef struct queue
{
data_type arr[N];
int front;
int rear;//一般情况下,将rear以及front置为有效元素的前一个元素, front == rear 时,队空
}Queue;
空队:pQueue->front == pQueue->rear;
入队:pQueue->rear = (pQueue->rear+1)% N; pQueue->arr[pQueue->rear] = item;
出队:pQueue->front = (pQueue->front+1)% N; *pData= pQueue->arr[pQueue->front];
(只能在队头出队)
未来解决循环队列中满队的问题,空出一个位置
案例:使用两个栈模拟一个队列
//入栈
printf("push:\n");
while(1)
{
scanf("%d",&item);
if(push(ps,item) == SKFULL)
{
break;
}
}
printf("pop after and push again:\n");
//出栈再进栈
while(1)
{
if((pop(ps,&item) == SKEMPTY) || push(pr,item) == SKFULL))
{
break;
}
printf("%-5d",item);
}
printf("\n");
//再出栈
printf("pop again:\n");
while(1)
{
if(pop(pr,&item) == SKEMPTY)
{
break;
}
printf("%-5d",item);
}
printf("\n");
day5
一.树
1.树:只有一个根节点 ,其余的节点不能相交
根没有前驱,叶没有后继
2.度数:一个节点子树的个数
3.树叶:度数为o 在最后得(终端节点)
4.边数:
5.深度:树的节点最大值
A:度数2 这个树的度数: 树叶:D,E,F 边数: 3, 4,3 深度:4
二.二叉树
1.二叉树要分左右孩子,一个的话也要分清楚
2.二叉树最多俩子节点 分左右子树
性质:
1.第i层上最多2^(i-1)
2.深度为k 最多 2^k -1
3.在任意一课二叉树中,树叶的数目比度数为2的节点的数目多1 n0=n2+1
eg、具有10个叶节点的二叉树有( )个度数为2的节点
A.8 B.9 C.10 D.11
10 = n2 + 1 n2= 9
4.满二叉树
5.完全二叉树:对于一课满二叉树,从下往上,从右往左,依次去掉若干个节点形成的数
6.顺序存储
7.链式存储
typedef struct treeNode
{
struct treeNode *lChild;
data_type data;
struct treeNode *rChild;
} Tree;
8.遍历
前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
void midOrder(Tree *pBoot)
{
if(NULL == pBoot)
{
return;
}
midOrder(pBoot->lChild);
printf("%d",pBoot->data);
midOrder(pBoot->rChild);
}
赫夫曼树:带权路径长度最短的树