单链表的运算 建立单链表 假设线性表中结点的数据类型是字符我们逐个输入这些字符型的结点并以换行符\n为输入条件结束标志符动态地建立单链表的常用方法有如下两种 () 头插法建表 ① 算法思路 从一个空表开始重复读入数据生成新结点将读入数据存放在新结点的数据域中然后将新结点插入到当前链表的表头上直到读入结束标志为止 具体方法 注意 该方法生成的链表的结点次序与输入顺序相反 ② 具体算法实现 LinkList CreatListF(void) {//返回单链表的头指针 char ch; LinkList head;//头指针 ListNode *s; //工作指针 head=NULL; //链表开始为空 ch=getchar(); //读入第个字符 while(ch!=\n){ s=(ListNode *)malloc(sizeof(ListNode));//生成新结点 s>data=ch; //将读入的数据放入新结点的数据域中 s>next=head; head=s; ch=getchar(); //读入下一字符 } return head; } () 尾插法建表 ① 算法思路 从一个空表开始重复读入数据生成新结点将读入数据存放在新结点的数据域中然后将新结点插入到当前链表的表尾上直到读入结束标志为止 具体方法 注意 ⒈采用尾插法建表生成的链表中结点的次序和输入顺序一致 ⒉必须增加一个尾指针r使其始终指向当前链表的尾结点 ② 具体算法实现 LinkList CreatListR(void) {//返回单链表的头指针 char ch; LinkList head;//头指针 ListNode *s*r; //工作指针 head=NULL; //链表开始为空 r=NULL;//尾指针初值为空 ch=getchar(); //读入第个字符 while(ch!=\n){ s=(ListNode *)malloc(sizeof(ListNode));//生成新结点 s>data=ch; //将读入的数据放入新结点的数据域中 if (head!=NULL) head=s;//新结点插入空表 else r>next=s;//将新结点插到*r之后 r=s;//尾指针指向新表尾 ch=getchar(); //读入下一字符 }//endwhile if (r!=NULL) r>next=NULL;//对于非空表将尾结点指针域置空head=s; return head; } 注意 ⒈开始结点插入的特殊处理 由于开始结点的位置是存放在头指针(指针变量)中而其余结点的位置是在其前趋结点的指针域中插入开始结点时要将头指针指向开始结点 ⒉空表和非空表的不同处理 若读入的第一个字符就是结束标志符则链表head是空表尾指针r亦为空结点*r不存在;否则链表head非空最后一个尾结点*r是终端结点应将其指针域置空 () 尾插法建带头结点的单链表 ①头结点及作用 头结点是在链表的开始结点之前附加一个结点它具有两个优点: ⒈由于开始结点的位置被存放在头结点的指针域中所以在链表的第一个位置上的操作就和在表的其它位置上操作一致无须进行特殊处理; ⒉无论链表是否为空其头指针都是指向头结点的非空指针(空表中头结点的指针域空)因此空表和非空表的处理也就统一了 ②带头结点的单链表 注意 头结点数据域的阴影表示该部分不存储信息在有的应用中可用于存放表长等附加信息 ③尾插法建带头结点链表算法 LinkList CreatListR(void) {//用尾插法建立带头结点的单链表 char ch; LinkList head=(ListNode *)malloc(sizeof(ListNode));//生成头结点 ListNode *s*r; //工作指针 r=head; // 尾指针初值也指向头结点 while((ch=getchar())!=\n){ s=(ListNode *)malloc(sizeof(ListNode));//生成新结点 s>data=ch; //将读入的数据放入新结点的数据域中 r>next=s; r=s; } r>next=NULL;//终端结点的指针域置空或空表的头结点指针域置空 return head; } 注意 上述算法里动态申请新结点空间时未加错误处理这对申请空间极少的程序而言不会出问题但在实用程序里尤其是对空间需求较大的程序凡是涉及动态申请空间一定要加入错误处理以防系统无空间可供分配 () 算法时间复杂度 以上三个算法的时间复杂度均为(n) |