关于数据结构栈和链表

关于数据结构栈和链表

基础任务一:实现一个数据结构栈,完成Init()、push()、pop()、getTop()等栈的基本函数。

我觉得栈相当于“先进后出”的一个数据结构,先放进去的数据后用,后放进去的数据先用,就大概一个有很多个格子的箱子,有节点。我们用“push"压栈,用”pop"出栈,用top变量记录栈顶的位置。实现方式分为数组实现和链表实现。

/**栈的初始化*/
void init(PSTACK);
/**压栈*/
void push(PSTACK,int);
/**出栈*/
int pop(PSTACK , int *);
/**遍历打印栈*/
void traverse(PSTACK);
/**是否为空栈*/
int isEmpty(PSTACK);
/**清空栈*/
void clearStack(PSTACK);

感受:我会觉得栈比数组要方便很多,因为数组要考虑下标,考虑不能直接引用数组,而要用a[1]这样的,也要考虑对一个空数组赋值,用for循环一个一个去填,在输出的时候,也不能说直接打印整个数组,但是呢,栈就很方便啊,不仅可以按一定顺序存,逆序用,还可以用指针指向某个元素或者节点,提高效率吧。

基础任务二:实现一个数据结构队列,完成Init()、EnQueue()、DeQueue()、getFront()等队列的基本函数。

首先先去学习关于队列的相关知识:队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。同样地它也有数组实现和链表实现两种方式。但是呢,简单数组实现中由于front之前的空间不能再次使用,就会出现,后面的元素输不进去,前面的空间又被浪费的局面,所以,可以试试循环数组?
末尾元素的下一位又是首元素,就可以利用了。BUT,怎么判断是空还是满呢,毕竟例如rear和front相邻时就无法辨别空还是满。

//入队功能函数 调用EnQueue函数
void EnterToQueue(SqQueue &Q)
{ 
    int n;
    QElemType e;
    int flag; 
    printf("请输入入队元素个数(>=1):\n"); 
    scanf("%d",&n); 
    for(int i=0;i<n;i++) 
    {   
        printf("请输入第%d个元素的值:",i+1);  
        scanf("%d",&e);  
        flag=EnQueue(Q,e);  
        if(flag)
                printf("%d已入队\n",e);  
        else 
        {
               printf("队已满!!!\n");break;
         } 
     }
}
//出队函数 调用DeQueue函数
void DeleteFromQueue(SqQueue &Q)
{ 
    int n;
    QElemType e;
    int flag; 
    
    printf("请输入出队元素个数(>=1):\n"); 
    scanf("%d",&n); 
    for(int i=0;i<n;i++) 
    {  
           flag=DeQueue(Q,e);  
           if(flag)
                printf("%d已出队\n",e);  
           else 
           {      
                printf("队已空!!!\n");break;
           } 
     }
}
//获得队头元素 调用GetHead函数
void GetHeadOfQueue(SqQueue Q)
{ 
     QElemType e;bool flag;  
     flag=GetHead(Q,e); 
     if(flag)printf("队头元素为:%d\n",e); 
     else printf("队已空!!!\n");
}

基础任务三:继续学习单向/双向/循环链表的基本操作。

Q1

栈的应用
1.LeetCode题号:20. 有效的括号(简单)给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。注意空字符串可被认为是有效字符串。

# include <stdio.h>
# include <stdlib.h>
# include <alloc.h>
bool isValid(char * s){
    if (s == NULL || s[0] == '\0') return true;
    char *stack = (char*)malloc(strlen(s)+1); int top =0;
    for (int i = 0; s[i]; ++i) {
        if (s[i] == '(' || s[i] == '[' || s[i] == '{') stack[top++] = s[i];
        else {
            if ((--top) < 0)                      return false;//先减减,让top指向栈顶元素
            if (s[i] == ')' && stack[top] != '(') return false;
            if (s[i] == ']' && stack[top] != '[') return false;
            if (s[i] == '}' && stack[top] != '{') return false;
        }
    }
    return (!top);//防止“【”这种类似情况
}

Q2

LeetCode题号: 150. 逆波兰表达式求值(中等)根据逆波兰表示法,求表达式的值。有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。说明:整数除法只保留整数部分。给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

int evalRPN(char ** tokens, int tokensSize)
{
    int stack[16384], top = 0;
    int num1, num2;
    
    for(int i = 0; i < tokensSize; i++){
        if(tokens[i][1] == '\0' && (tokens[i][0] == '+' || tokens[i][0] == '-' || tokens[i][0] == '*' || tokens[i][0] == '/')){
            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;
                default :
                    break;
            }
        }else{
            stack[top++] = atoi(tokens[i]);
        }   
    }
    
    return stack[--top];
}

Q3

链表的应用1.LeetCode题号: 21. 合并两个有序链表(简单)将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if(l1 == NULL) return l2;
    if(l2 == NULL) return l1;
    
    struct ListNode newhead, *p1, *p2;
    newhead.next = l1;
    l1 = &newhead;
    
    while(l2 != NULL) {
        p1 = l1->next;
        p2 = l2->next;
        if(p1 == NULL) {
            l1->next = l2;
            break;
        }
        if(l2->val <= p1->val) {
            l2->next = l1->next;
            l1->next = l2;
            l2 = p2;
        }
        l1 = l1->next;
    }
    return newhead.next;
}

Q4

LeetCode题号: 2. 两数相加(中等)给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

int c=0;
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
    if(l1==NULL&&l2==NULL&&c==0)return NULL;
    l1!=NULL?(c+=l1->val,l1=l1->next):(c+=0);
    l2!=NULL?(c+=l2->val,l2=l2->next):(c+=0);
    struct ListNode *cur=(struct ListNode *)malloc(sizeof(struct ListNode));
    cur->val=c%10;
    c=c/10;
    cur->next=addTwoNumbers(l1,l2);
    return cur;
}

我总结一下,以上各题凡是看起来不像我水平的全部来自leetcode题解中各位大神,我真的觉得我学得慢而且上手也慢,目前我还在指针的应用中挣扎,看了一点链表,栈和数据结果列看了一大部分。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值