本文分为三个方向总结线性表,队列,堆栈。
一,线性表:
1,定义:
1 typedef int position; 2 typedef struct LNode *List; 3 struct LNode { 4 ElementType *Data; 5 Position Last; 6 };
就是定义一个结构,结构里面分别是这个表的数据(也就是一个数组),还有数组的最后一个元素
2,初始化
1 List makeempty(){ 2 List T; 3 T= (List)malloc(sizeof(struct LNode)); 4 T->Last = -1; 5 return T; 6 }
3,查找:
一共有看到两种版本:
第一个Position Find(List L,ElementType X){ Position i = 0; while(i<=L->Last&&L->Data[i]!=x){ i++; } if(i>L->Last){ return ERROR; }else{ return i; } }
Find (List L,ElementType X){ Position i; while(i<=L->Last){ if(x == L->Data[i]){ return i; } i++; } return ERROR; }
第一个方法是通过遍历停到与需要查找的值相等的位置,然后停下来返回下标,第二种就是在遍历的过程中直接找
4,插入:
首先要明确一个我一直忘记的事情就是没有判断是否表满,需要插入的位置是否表满,整体的思路就是从后往前遍历,从L->last开始往前到需要插入的位置,把每一个i的值赋给前一个位置。
bool Insert(List L,Position p,ElementType X){ if(L->Last = MaxSize -1){ printf("full"); return false; } if(P>L->Last||P<0){ printf("ERROR"); return false; } for(int i=L->Last;i>=P;i--){ L->Data[i+1] = L->Data[i]; } L->Data[P] = X; L->Last++; return true; }
在p的位置,把p的值给赋给p+1位置,然后再把x插入p的位置
5,删除:
其实删除和插入是一样的只是移动的方向不是一样的,删除是从被删除的点开始把后面一个值赋给前一个的值。还有一个细节就是插入的时候非法位置是不包括最后一个的因为可以再最后一个位置插入值,但是在删除中最后L->last+1的位置是没有值的
bool Delete(List L,Position P){ if(L->Last == -1){ printf("empty"); return false; } if(L->Last<P||P<0){ printf("illegal"); return false; } for(Position i = P+1,i<=L->Last;i++){ L->Data[i-1] = L->Data[i]; } L->Last--; return true; }
我觉得需要注意的就是这个循环的控制条件,是从p+1开始的,如果这个条件错的话很可能会导致段错误。
二,队列
1,定义:
typedef int Position; struct QNode { ElementType *Data; /* 存储元素的数组 */ Position Front, Rear; /* 队列的头、尾指针 */ int MaxSize; /* 队列最大容量 */ }; typedef struct QNode *Queue;
2,创建空队列:
Queue CreateQueue( int MaxSize ) { Queue Q = (Queue)malloc(sizeof(struct QNode)); Q->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType)); Q->Front = Q->Rear = 0; Q->MaxSize = MaxSize; return Q; }
队列需要给两个部分分配空间,一个是整个队列结构,一个是队列结构中的Data数组,那么为什么上面的有序数组不需要这样分配空间呢?有序数组不是在结构体中也有一个数组嘛?我的理解是这个地方的队列是有最大容量的,上面的有序数组是一个指针只需要一个Last卡住最后的位置,而且有序表的创建是用插入的方式,需要一个数插入一个数。所以就没必要一开始就把相应的空间给定死了。
3,判断队列是否为满:
bool IsFull( Queue Q ) { return ((Q->Rear+1)%Q->MaxSize == Q->Front); }
队列如果是空的满,那么相应的下标应该是比Maxsize小1的,所以如果Q->rear+1%Maxsize是0,而且Q->front也是0(因为可能存在出队的情况front不在0的位置)的话就说明队列是满的。只有这样写的话才会保证头和尾都处于顶点。
4,判断队列是否为空:
bool IsEmpty( Queue Q ) { return (Q->Front == Q->Rear); }
这个判断是否为空也很经常作为队列遍历的循环条件。注意和判断队列是否为满区分开来
5,插入元素:
bool AddQ( Queue Q, ElementType X ) { if ( IsFull(Q) ) { printf("队列满"); return false; } else { Q->Rear = (Q->Rear+1)%Q->MaxSize; Q->Data[Q->Rear] = X; return true; } }
首先根据前面的经验,一旦要插入和删除元素的时候一定要判断所要插入的空间是不是满了,判断完了之后就是插入的过程,前面没有说这个队列的特性是顺环队列,不是我之前学的顺序队列,我之前学的队列是tail可以一直往前走,只要保证tail始终比最后一个元素的下标大一就好了,但是这个地方的队列的大小都是固定的所以会存在一个循环的问题。这个的rear的变化就是一旦rear为最后一个下标的话,就重置到第一个位置来插入元素了。
6,删除
之前的插入时从为插入,那么删除的话就是从头删除,只要head++不就好了
ElementType DeleteQ( Queue Q ) { if ( IsEmpty(Q) ) { printf("队列空"); return ERROR; } else { Q->Front =(Q->Front+1)%Q->MaxSize; return Q->Data[Q->Front]; } }
这个地方的删除其实也是一样,一旦一直删除的话,删除到最后一个数字之后,你要继续把front放到开头去,然后要返回所删除掉的值。
三,堆栈
1,定义:
typedef int Position; struct SNode { ElementType *Data; /* 存储元素的数组 */ Position Top; /* 栈顶指针 */ int MaxSize; /* 堆栈最大容量 */ };
2,判断是否栈满:
bool IsFull( Stack S ) { return (S->Top == S->MaxSize-1); }
3,判空:
bool IsEmpty( Stack S ) { return (S->Top == -1); }
记住当top是-1的时候说明栈空,这个也是堆栈初始化必须做的
4,入栈:
bool Push( Stack S, ElementType X ) { if ( IsFull(S) ) { printf("堆栈满"); return false; } else { S->Data[++(S->Top)] = X; return true; } }
其实在目前做题中好像我很少会用 这个方式来压入元素,其实直接写也就是一行的代码。
5,出栈:
ElementType Pop( Stack S ) { if ( IsEmpty(S) ) { printf("堆栈空"); return ERROR; /* ERROR是ElementType的特殊值,标志错误 */ } else return ( S->Data[(S->Top)--] ); }
感觉最近一段时间有点厌学了,数据结构还是蛮难学的,竞赛的书也难看的要死,pb也还没有入门 ( ・᷄⊖・᷅ )┌∩┐,我感觉还不如沉淀一段时间来巩固一下,学到树就停一下把pta中树的题目给做完把!(感觉题目都好难做 ( ・᷄⊖・᷅ )┌∩┐ )。然后我还想把py的爬虫学完还有一些比较有意思的库,后面学完也丢到博客里面。