#include<stdio.h> #include <stdlib.h> typedef int ElemType; typedef struct LNode{ ElemType data; struct LNode *next; }LNode,*LinkList; bool InitList(LinkList &L){ //带头节点(没有值的节点,只有next指针的结构体初始化,且头节点值本就为空 L = (LNode *)malloc(sizeof(LNode)); if(L==NULL) //内存不足,分配失败 return false; L->next=NULL; //头节点之后暂时还没有节点 return true; } //bool InitList(LinkList &L){ //不带头节点的指针初始化 // L=NULL; // return true; //} bool Empty(LinkList L){ //判断有头节点的单链表是否为空 if(L->next==NULL) return true; else return false; } bool Empty2(LinkList L){ //判断无头节点的单链表是否为空,这里只是判断,所以不需要用"&"引用,不改变值 if(L==NULL) return true; else return false; } //bool Empty(LinkList L){ //判断无头节点单链表是否为空的简洁写法 // return (L==NULL); //} bool ListInsert(LinkList &L,int i, ElemType e){ //带头节点的单链表根据位置i插入节点 if(i<1) return false; LNode *p=L; int j=0; while(p!=NULL&&j<i-1){ //循环找到第i-1个节点,如果在j=i-1之前到达了空节点,说明插入的位置太大,单链表没那么长 p=p->next; j++; } if(p==NULL) //说明循环终止的原因是找到了空节点,即i值不合法 return false; LNode *s=(LNode *)malloc(sizeof(LNode)); s->next=p->next; p->next=s; // LNode c; //也可以这么写,很直白,但是数据是创建在栈上,而C语言的栈内存小,用malloc是创建在堆上,推荐上面的写法。 // c.data=e; // c.next=p->next; // p->next=&c; return true; } bool ListInsert_2(LinkList &L,int i,ElemType e){ //不带头节点的单链表插入节点 if(i<1) return false; if(i==1){ LNode *s=(LNode *)malloc(sizeof(LNode)); s->data=e; s->next=L->next; L->next=s; return true; } LNode *p; p=L; int j=1; while(p!=NULL&&j<i-1){ p=p->next; j++; } if(p=NULL) return false; LNode *s=(LNode *)malloc(sizeof(LNode)); s->next=p->next; p->next=s; return true; } //后插操作:在p节点之后插入data为e的结点 bool InsertNextNode(LNode *p,ElemType e){ if(p==NULL) //判断传过来的结点是否为空 return false; LNode *s=(LNode *)malloc(sizeof(LNode)); if(s==NULL) return false; //判断内存不够,无法分配 s->data=e; s->next=p->next; p->next=s; return true; } //前插操作,给定链表指针可以这样写 //bool InsertPriorNode(LinkList L,LNode *p,ElemType e){ // 但这样时间复杂度比较高,而且LinkList L不一定可以获得 //} //第二种前擦操作,通过更换数据,达到逻辑上的效果 bool InsertPriorNode(LNode *p,ElemType e){ if(p==NULL) return false; LNode *s=(LNode *)malloc(sizeof(LNode)); s->next=p->next; p->next=s; //新结点s连到p之后 s->data=p->data; //将p中元素复制到s中 p->data=e; //p中元素覆盖为e return true; }//时间复杂度仅为O(1) //按位删除结点 bool ListDelete(LinkList L,int i,ElemType &e){ if(i<1) return false; LNode *p; p=L; int j=1; while(p!=NULL&&j<i-1){ j++; p=p->next; } if(p==NULL) return false; if(p->next==NULL) return false; LNode *q=p->next; //这里之所以要创建一个LNode,是因为最后要free这个删除的节点,解除内存 e=q->data; p->next=q->next; free(q); } //删除指定结点p bool DeleteNode(LNode *p){ if(p==NULL) return false; LNode *q=p->next; //偷天换日,通过把p下个结点q的数据复制给结点p,再将q的下一个结点连接到p的next指针,最后free p->data=q->data; //可达到将p结点删除的逻辑结果 p->next=q->next; ///如果这个单链表就只有一个结点p,那么这里就会出错,因为q为null,所以如果只有一个结点p, free(q); ///就只能从头开始遍历删除 return true; } //根据位置i查找结点 LNode *GetElem(LinkList L,int i){ ///这里是LNode *,因为最后返回的是一个LNode指针,C语言不是面对对象的,所以不能返回一个结构体 if(i<0) return NULL; LNode *p=L; int j=0; while(p!=NULL&&j<i){ p=p->next; j++; } return p; } //按值查找 LNode *LocateElem(LinkList L,ElemType e){ //如果ElemType是更复杂的结构类型,在本函数中是不可以用==进行比较的 LNode *p=L->next; while(p->data!=e && p!=NULL) p=p->next; return p; } //尾插法建立单链表 LinkList List_Taillnsert(LinkList &L){ L=(LNode *)malloc(sizeof(LNode)); int x; LNode *r=L; scanf("%d",&x); while (x!=9999){ LNode *s=(LNode *)malloc(sizeof(LNode)); s->data=x; r->next=s; r=s; scanf("%d",&x); } r->next=NULL; return L; } ///头插法插入的顺序是相反的,比如先后输入10,20,30,最后得到的链表顺序是30,20,10 ///所以可以通过头插法的代码实现链表的逆置 //头插法建立单链表,其实就是一直在头节点后面插入一个结点,可用InsertNextNode函数处理 LinkList List_HeadInsert(LinkList &L){ LNode *s; L=(LNode *)malloc(sizeof(LNode)); L->next=NULL; ///为什么这里要将next置为0,而尾插法不要 int x; ///因为头插法可能L->next指向一个脏数据,会导致后面新建立的结点 scanf("%d",&x); ///的next指针指向这个脏数据,导致链表错误 while(x!=9999){ //当输入9999时链表初始化终止 s=(LNode *)malloc(sizeof(LNode)); s->data=x; s->next=L->next; L->next=s; scanf("%d",&x); } return L; } //头插逆置法 LinkList List_Inverse(LinkList &L){ LNode *s,*p; //定义一个代替原链表除了头节点的s指针,和当前要插入的p s=L->next; //s指向L->next的结点 L->next=NULL; ///将L重置为一个只有头节点的空链表 while(s!=NULL){ //当s为NULL的时候,说明所有结点逆置完毕 s=s->next; p=s; p->next=L->next; L->next=p; } return L; } void dispList(LinkList L){ LNode *p=L->next; while(p!=NULL){ int x=p->data; printf("%d,",x); p=p->next; } return; } int main(){ LinkList L; //声明一个指向Lnode节点的指针 InitList(L); dispList(List_Taillnsert(L)); }
数据结构单链表所有操作,创建,初始,增删改查逆置
最新推荐文章于 2024-05-17 23:32:03 发布