鲸了!数据结构居然如此复杂!
栈 栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。 栈可以根据是否可以动态增加存储空间,分为动态栈和静态栈两种。
动态栈 动态栈是建立在 malloc 函数的基础之上的一种栈结构
动态栈的数据结构定义 1 2 3 4 5 6 7 8 9 10 11 typedef struct Node //定义一个链表式结点结构体{ int data; struct Node * last ; }*node; typedef struct Stack //定义链式栈结构体{ node top; int count; }stack ;
由于动态栈的数据是可以变化的。因此在动态栈中是没有 init()操作的,每一次 push 操作都会使得动态栈的大小动态扩大。
动态栈的入栈操作函数 1 2 3 4 5 6 7 8 void push (stack *S,int n) { node curs = (node)malloc (sizeof (struct Node)); curs -> data = n; curs -> last = S->top; S -> top = curs; S -> count ++; }
动态栈的出栈操作函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 int pop (stack *S) { int output; node curs; if (S->count == 0 ){ printf ("Error,Stack is empty!\n" ); exit (1 ); } curs = S->top; output = curs->data; S->top = curs->last; free (curs); S->count--; return output; }
动态栈的取栈顶元素函数 1 2 3 4 5 6 7 8 9 int Gettop (stack *S) { if (S->count == 0 ) { printf ("Error,Stack is empty!\n" ); exit (1 ); } return S->top->data; }
静态栈 静态栈是建立在静态数组的基础之上的一种栈结构。
静态栈的数据结构定义 1 2 3 4 5 6 #define MAXSIZE 1000 typedef struct Stack //定义栈{ int data[MAXSIZE]; int top; }stack ;
静态栈的初始化函数 1 2 3 4 5 stack Init () { stack s; s->top = -1 ; return s; }
静态栈的进栈操作函数 1 2 3 4 5 6 7 8 9 10 11 12 int Push (stack &s,int n) { if (s->top == P-1 ){ printf ("stack full\n" ); exit (1 ); } s->top++; s->data[s->top] = n; if (s->top == P-1 ){ return 0 ; } return 1 ; }
注意 由于静态表并不会自动增加存储空间,因此我们需要在进栈结束后判断栈是否已满,避免发生溢出情况。
静态栈的出栈操作函数 1 2 3 4 5 6 7 8 9 10 int Pop (stack &s) { int n; if (s->top == -1 ){ printf ("stack empty\n" ); exit (1 ); } n = s->data[s->top]; s->top--; return n; }
静态栈的取栈顶元素函数 1 2 3 4 5 6 7 int Gettop (stack *s) { if (s->top == -1 ){ printf ("Error,Stack is empty!\n" ); exit (1 ); } return s->data[s->top]; }
栈的应用 LeetCode 20 有效的括号 思路 遇左括号就入栈,遇右括号就把栈顶元素拿出来比对。 如果栈空(用 top 指针判断),则为 True。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 bool isValid (char * s) { if ( s == NULL ) return false ; char * stack = (char * ) malloc ( sizeof (char ) * ( strlen (s)+1 ) ); int top = 0 ; for ( int i=0 ; s[i]!='\0' ; i++) { if (s[i]=='(' || s[i]=='[' || s[i]=='{' ) stack [++top] = s[i]; else if ( (s[i]==')' &&stack [top]=='(' ) || (s[i]==']' &&stack [top]=='[' ) || (s[i]=='}' &&stack [top]=='{' ) ) top--; else return false ; } if ( stack != NULL ) { free (stack ); stack = NULL ; } if ( top == 0 ) return true ; else return false ; }
LeetCode 150 逆波兰表达式求值 思路 写个循环遍历字符串 碰到数字就压进栈 遇到运算符就把栈顶的两个元素弹出来 然后算了之后的结果再压进去 直到最后把栈里的最后一个元素输出即可
代码 这题真的很迷,每次运行都报数组越界,无奈只好放弃,就把有 bug 的源代码贴上来好了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 int evalRPN (char ** tokens, int tokensSize) { int stack [10000 ], top = 0 ; int num1, num2; int i; for (i = 0 ; i < tokensSize; i++){ if (tokens[i] == '+' || tokens[i] == '-' || tokens[i] == '*' || tokens[i] == '/' ){ num2 = stack [--top]; num1 = stack [--top]; switch (tokens[i][0 ]){ case '-' : stack [top++] = num1 - num2; break ; case '+' : stack [top++] = num1 + num2; break ; case '* ' : stack [top++] = num1 * num2; break ; case '/' : stack [top++] = num1 / num2; break ; } } else { stack [top++] = atoi(tokens[i]); } } return stack [--top]; }
队列 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
队列的实现 队列的数据结构定义 1 2 3 4 5 6 7 8 9 10 typedef struct Node //数据域{ int data; struct Node * next ; }Node,*DNode; typedef struct Queue //指针域{ DNode front; DNode rear; }Queue,*DQueue;
队列的初始化函数 1 2 3 4 void initQueue (DQueue Q) { Q=(DQueue)malloc (sizeof (Queue)); Q->front=Q->rear=NULL ; }
队列的入队操作函数 1 2 3 4 5 6 7 8 9 10 11 12 void inQueue (DQueue Q,int n) { DNode q; q=(DNode)malloc (sizeof (Node)); q->next=NULL ; q->data=n;将值放入节点中 if (Q->rear==NULL ) Q->front=Q->rear=q; else { Q->rear->next=q; Q->rear=q; } }
由于队的存储空间大小是动态变化的,因此我们不需要判断队列是否已满。
队列的出队操作函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int outQueue (DQueue Q,int x) { if (Q->front==NULL || Q->rear==NULL ) return -1 ; DNode q; q=Q->front; if (Q->front==Q->rear) Q->front=Q->rear=NULL ; else Q->front=Q->front->next; x=q->data; free (q); return x; }
队列的取队尾元素函数 1 2 3 4 5 int getFront (DQueue Q) { if (Q->front==NULL || Q->rear==NULL ) return -1 ; return Q->front->data; }
队列的应用 LeetCode 21 合并两个有序链表 思路 定义一个新链表。 比较两个原链表中元素的大小,并把它放到新链表中。 然后再把放入了新元素的链表的指针向后移一个节点,没有放入新元素的链表的指针不动。 如果一个链表指针已经指向队尾,那么就把另外一个链表之后的所有节点原封不动全部放入新链表中。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 struct ListNode* mergeTwoLists (struct ListNode* l1, struct ListNode* l2) { struct ListNode output ; output.next = NULL ; struct ListNode * ear = &output ; struct ListNode * node = NULL ; while (l1 && l2){ rear->next = l1->val < l2->val ? l1 : l2; if (l1->val < l2->val){ l1 = l1->next; } else { l2 = l2->next; } rear = rear->next; } if (l1){ rear->next = l1; } if (l2){ rear->next = l2; } return output.next; }
LeetCode 2 两数相加 思路 懒得写了全部写在代码的注释当中……
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 int value = 0 ;struct ListNode* addTwoNumbers (struct ListNode* l1, struct ListNode* l2) { if (l1==NULL &&l2==NULL &&value==0 ){ return NULL ; } if (l1!=NULL ){ value+=l1->val; l1=l1->next; } else { value+=0 ; }; if (l2!=NULL ){ value+=l2->val; l2=l2->next; } else { value+=0 ; } struct ListNode *outList =(struct ListNode *)malloc (sizeof (struct ListNode )); outList->val=value%10 ; value=value/10 ; outList->next=addTwoNumbers(l1,l2); return outList; }
还有两道困难题…… 就先咕为敬了,告辞 有空再补