C语言数据结构单链表代码细节理解

123 阅读4分钟

巩固知识,做下笔记,如有错误请指正

一.链式存储结构的创建

 typedef struct Node{
	          Student data;
	          struct Node *next;
      }Node,*LinkList;
  1. data 是结点的数据域,用来存放具体的数据,*next是指针型变量,用来存放下一个节点的地址
  2. *LinkList用来创建指针类型的变量,即创建指向节点的指针,例:LinkList p
  3. Node用来创建节点,例:new Node
  4. p=new Node是指将节点的地址赋给p,使指针P指向该节点
  5. 其实*LinkList p=Node *p,为了代码的可读性,以及方便对指针和节点的区分才设置两个名称

二.方法传值 & 的理解

int main(){
	LinkList L;
      InitList(L);
	     void InitList(LinkList &L){
	            L=new Node;
	            if(!L) return ;
	             L->next=NULL;
	            printf("Enter successfully!\n");	
}
  1. 用LinkList创建指针变量L(即头指针或链表),L的值为链表的引用,而&可以获取变量的引用地址,所以用&L作为形参接收数值

三.单链表的具体操作

1.几个基本原则

  • 使代码具有简约性(精简删除代码),统一性(特殊操作和一般操作代码尽量相同),排错性(错误的输入自动提示或返回)
  • 插入等改变指针指向的的操作秉持先后再前的原则,以避免节点地址被覆盖的情况
  • 无用的节点及时释放
  • 必要时添加辅助指针降低操作难度 例:尾指针 (把头指针和移动指针p称为基本指针)
  • 头节点的序号为0,首元节点的序号为1

2.头节点的作用

  • 是链表在头节点后插入,删除和其他操作具有相同的代码,使代码具有统一
  • 无论链表是否为空,头指针始终是指向头节点的非空指针,清空链表后再进行录入时,不必再对头指针 L=new Node

3.初始化

 int InitList(LinkList &L){
             L=new Node;//创建头节点,并将头节点的引用赋值给指针L,使指针L指向头节点
             L->next=NULL;//头节点的指针域置为空
              return 1;
           }

创建了一个只有头指针和头节点的空表,头节点的数据域可以存数据也可以不存

stateDiagram-v2
[L] --> data|NULL

4.取值

int GetElem(LinkList &L,int i,ElemType &e){//ElemTpye是指所有类型,需替换为int,double等具体类型
          LinkList p=new Node;
           p=L->next; int j=1;
            while(p&&j<i){
                      p=p->next; j++;
            }
             if(!p||j>i) return ;
             e=p->data;
             return 1;
            }

因首元节点开始有数据,所以将移动指针p指向首元节点,从首元节点开始,使用while循环移动指针移动指针至想要获取的元素

5.查找

与取值操作相同,指针从首元节点出发

Node *LocatElem(LinkList &L,ElemType e){
       LinkList p=new Node;
       p=L->next;
        while(!p&&p->data!=e){
          p=p->next
          }
         return p;//若查找成功返回p,若不成功,这时p=p->next=NULL返回空   
     }   

6.插入

与取值和查找不同,插入操作需要指针p从头节点开始出发,因为(1)插入操作的位置是ai-1和ai之间的位置。(2)而且插入操作需要改变被插入位置前后节点的引用,而链表很难获取前驱,很容易获取后继,所以指针p应当指向被插入位置的前一个节点。特殊的在首元节点前插入需要P指针指向头节点即P=L。

int ListInert(LinkList &l,int i,ElemType e){
//i插入的位置,e为插入位置的数据
     LinkList p=new Node;
     LinkList s=new Node;
      p=L; j=0;//出发位置为0
      while(p&&j<i-1){//while循环移动指针,若while循环中为p->next则指针不能移动至最后一个指针,最后一个节点前就不能插入
          p=p->next;//若一直未能查到(i的值大于j-1),最后一次进入循环后,p的值变成NULL
          h++;
          }
          if(!p||j>i-1)  return 0;   
          s->data=e;
          s->next=p->next;
          p->nex=s;
          }         

7.删除

删除该节点即将前一节点指针域置为空,然后删除释放该节点

int ListDelete(LinkList &L,int i){
     LinkList p=new Node;
     LinkList q;
      p=L; j=0;
       while(p->next&&j<i-1){//j=i-1控制循环次数即指针移动次数,指针所在位置是删除节点之前,永远比删除节点序号小1
          p=p->next; j++;
          }
          if(!(->next)|j>-1) return 0;
           q=p->next;
           p->next=q->next;
           delete q;
            return 1
           }

8.创建单链表

(1)前插法

在首元节点前插入数据

void CreatList_H(LinkList &L,int n){
       L=new Node;
       L->next=NULL;
        for(int i=0;i<n;i++){
          LinkList p=new Node;//创建新节点
           cin>>p->data;
           p->next=L->next;//若没有首元节点则新节点指针域为空
           L->next-p;
           }
           }

(2)尾插法

在最后的节点后插入节点,需要引入辅助指针尾指针,尾指针始终指向最后一个节点

void CreatList_R(LinkList &L,int n){
       L=new Node;
       L->next=NULL;
        LinkList s=new Node;//创建尾指针
        s=L;
         for(int i=0;i<n;i++){
            LinkList p=new Node;
            cin>>p->data;
            s->next=p;//只考虑一个节点的指针指向,该句与下一句顺序可以相反
            p->next=NULL;
            s=p;//刷新s指向尾节点

先录入数据,再建立节点间的联系,最后将新节点地址赋给s刷新尾指针