关于 !p 如何理解.符号 ! 用于把真变假, 假变真例如,!5的值是0(false,假), !0的值是1(true,真)假设链表L有5个数据,分别是 10,20,30,40,50位置范围是从第1位到第5位.假设要找第6个元素(结点),可以看到,i=6已经超出范围.执行语句while(p && j<i)之后,此时,i,j,p的数值分别是:i=6, j=6, p=00000000, !p=1p等于空指针(NULL),也就是p等于0, 而!p等于1(这是true,真)由于 !p是真, j>i是假, 满足 if(!p || j>i) 的条件,所以,执行return ERROR, 函数GetElem()返回ERRORif(!p || j>i) // 第i个元素不存在{   return ERROR;}e=p->data; // 取第i个元素return OK;假设要找第0个元素(结点),可以看到,i=0超出范围.执行语句while(p && j<i)之后,此时,i,j,p的数值分别是:i=0, j=1, p=00942A70, !p=0, e=10p等于第1个结点的指针,p不等于0, 而!p等于0(这是false,假)由于 !p是假,j>i是真, 满足 if(!p || j>i) 的条件,所以,执行return ERROR, 函数GetElem()返回ERROR假设要找第3个元素(结点),i=3在范围之内.执行语句while(p && j<i)之后,此时,i,j,p的数值分别是:i=3, j=3, p=00942A90, !p=0, e=30p等于第3个结点的指针,p不等于0, 而!p等于0(这是false,假)由于 !p是假,j>i是假, 不满足 if(!p || j>i) 的条件,所以,继续往下执行e=p->data以及return OK, 函数GetElem()返回OK测试结果:链表里的数据有: 10 20 30 40 50测试: i=6, j=6, p=00000000, !p=1第6位超出链表的范围.测试: i=0, j=1, p=00942A70, !p=0, e=10第0位超出链表的范围.测试: i=3, j=3, p=00942A90, !p=0, e=30第3个结点是 30//用C++编译器进行测试#include<stdio.h>#include<stdlib.h>#define OVERFLOW -1#define ERROR     0#define OK        1typedef int ElemType;typedef int Status;typedef struct LNode{    ElemType data;    struct LNode *next;}LNode, *LinkList;//创建链表void CreateList(LinkList &L,int n){    LinkList newNode; //新结点    LinkList ptr;     //当前结点    int i;    //这是带头结点的单链表    L=(LinkList)malloc(sizeof(LNode));    L->next=NULL;    ptr=L;    for(i=0;i<n;i++)    {        newNode=(LinkList)malloc(sizeof(LNode));        newNode->data=(i+1)*10;        newNode->next=NULL;        ptr->next=newNode;        ptr=newNode;    }}//打印链表void DispList(LinkList L){    LinkList ptr;     //当前结点    ptr=L->next;    if(ptr==NULL)    {        printf("链表没有数据.\n");        return;    }    while(ptr != NULL)    {        printf("%d ",ptr->data);        ptr=ptr->next;    }    printf("\n");}//查找第i个结点Status GetElem(LinkList L,int i,ElemType &e) // 算法2.8{    // L为带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR    int j=1; // j为计数器    LinkList p=L->next; // p指向第一个结点    while(p && j<i) // 顺指针向后查找,直到p指向第i个元素或p为空    {        p=p->next;        j++;    }    ////////测试    if(p==NULL)    {        printf("\n测试: i=%d, j=%d, p=%p, !p=%x\n",i,j,p,!p);    }    else    {        printf("\n测试: i=%d, j=%d, p=%p, !p=%x, e=%d\n",i,j,p,!p,p->data);    }    ////////    if(!p || j>i) // 第i个元素不存在    {        return ERROR;    }    e=p->data; // 取第i个元素    return OK;}int main(){    LinkList L;    int i;    ElemType e;    Status ret;    CreateList(L,5);    printf("链表里的数据有: ");    DispList(L);    i = 6;    ret=GetElem(L,i,e);    if(ret==ERROR)    {        printf("第%d位超出链表的范围.\n",i);    }    else    {        printf("第 %d 个结点是 %d\n",i,e);    }    i = 0;    ret=GetElem(L,i,e);    if(ret==ERROR)    {        printf("第%d位超出链表的范围.\n",i);    }    else    {        printf("第%d个结点是 %d\n",i,e);    }    i = 3;    ret=GetElem(L,i,e);    if(ret==ERROR)    {        printf("第%d位超出链表的范围.\n",i);    }    else    {        printf("第%d个结点是 %d\n",i,e);    }    return 0;}

这种情况就是为了保证考虑周全,当i取0的时候不就是符合条件了嘛,个人理解就是严谨性吧 本回答被提问者采纳

数据结构有很多 最好贴出全文 不然得不到好答案…… 更多追问追答 追问 这个算法能不能删除最后一个元素,也就是说,L共有n个元素,删除第n个元素。执行完while语句,j=n-1,p也到了第n-1个结点,再执行if,p->next为空,if成立,返回ERROR.对不? 先谢啦! 本回答由提问者推荐

严蔚敏数据结构 下面的代码if(!p||j&gt;i)中!p怎么理解啊 第1张

没错,!p指p是空指针

当你传参数i>n时,while语句处跳出条件是p为空了,此时的 j 必然小于 i ,那么if语句中的(!p)就为真了,则返回error。 本回答由提问者推荐

严蔚敏数据结构 下面的代码if(!p||j&gt;i)中!p怎么理解啊 第2张

!p->next什么意思 相当于p->next==NULL

线性表有顺序存储和链式存储,数据结构的代码都比较多,不是几行就可以了,下面是链表(线性表的链式存储结构)的基本操作,你看看#include "stdio.h"#include "stdlib.h"#include"string.h"#define OK  1#define ERROR 0typedef char ElemType[10];//数据元素类型typedef struct LNode{     //单链表结构  ElemType data;  struct LNode *next;}LNode,*LinkList;void CreateList_L(LinkList &L,int n){//顺序创建有n个结点的单链表 LinkList p,q; int i; L=(LinkList)malloc(sizeof(LNode));//生成头节点 if(!L) return ; L->next=NULL;q=L; for(i=1;i<=n;++i)  {  p=(LinkList)malloc(sizeof(LNode));//生成新节点  printf("Input NO.%d  :",i);  scanf("%s",p->data);  p->next=NULL;q->next=p;  q=p;  }}void Display_L(LinkList L){//L为头指针,显示单链表的每个元素 LinkList p=L->next; while(p)  {  printf("%s\t",p->data); p=p->next;  } printf("\n");}int GetElem_L(LinkList L,int i,ElemType e){//L为单链表的头指针,取为位序为i的元素值,并赋值给变量e LinkList p=L->next; int j=1; while(p&&j<i)  {  p=p->next; j++;  } if(!p||j>i) return ERROR; strcpy(e,p->data);return OK;}int ListInsert_L(LinkList &L,int i,ElemType e)  {//L为单链表的头指针,表示在位序为i的元素前插入数据e LinkList p=L,s;int j=0; while(p&&j<i-1) //定位在第i-1节点上  {  p=p->next; ++j;  } if(!p||j>i-1) return ERROR;//i值不合理 s=(LinkList)malloc(sizeof(LNode)); strcpy(s->data,e); s->next=p->next; p->next=s; return OK;}int ListDelete_L(LinkList &L,int i,ElemType e){//L为单链表的头指针,删除位序为i的数据元素,并将其值赋值给e LinkList p=L,q; int j=0; while(p&&j<i-1)  {  p=p->next; ++j;  } if(!p||j>i-1) return ERROR;//i值不合理 q=p->next;p->next =q->next ;//删除结点  strcpy(e,q->data );free(q);//释放结点 return OK;}void main(){ LinkList L; ElemType e; int n; printf("请输入单链表的长度n="); scanf("%d",&n); CreateList_L(L,n); printf("\n原始单链表是:");Display_L(L); if(GetElem_L(L,3,e))printf("\n3号结点的内容是:%s\n",e); if(ListDelete_L(L,6,e)) printf("\n删除6号结点后的单链表是:");Display_L(L); if(ListInsert_L(L,4,"李")) printf("\n在4号结点前插入后的单链表是:\n");Display_L(L);}