链表 大体的框架 单链表的定义和基本操作 定义 什么是单链表每个节点包括数据和指向下一个元素的指针 优点:无需连续的存储空间 #定义一个单链表(不带头节点) typedef struct LNode { //定义单链表节点类型 ElemType data; //每个节点存放一个数据元素 struct LNode * next; //指针指向下一个节点 } LNode,* LinkList; //LNode强调是一个节点,LinkList强调是一个链表 LinkList p= ( LNode* ) malloc ( sizeof ( LNode) ) ; //增加一个新的节点,并用指针p指向该节点 } ; 初始化(不带头节点) boolInitList ( LinkList& L) { L= NULL ; return true; } 判空(不带头节点) boolEmpty ( LinkList L) { if ( L== NULL ) return true; else return false; } #定义一个单链表(带头节点) typedef struct LNode { Elemtype data; struct LNode * next; } LNode, * LinkList; 初始化一个单链表(带头节点) boolInitList ( LinkList& L) { L= ( LNode* ) malloc ( sizeof ( LNode) ) ; if ( L== NULL ) //内存不足,分配失败 return false L-> next= NULL ; //头节点之后暂时还没有节点 return true; } 判空(带头节点) boolEmpty ( LinkList L) { if ( L-> next== NULL ) return false; else return false; } #按位序插入 带头结点 在第i个位序插入指定元素e 头节点可以看作第0个节点 boolListInsert ( LinkList& L, int i, ElemType e) { if ( i< 1 ) //判断输入位序是否合法 return false; LNode* p; int j= 0 ; //位序计数器 p= L; //头节点是第0个节点 while ( p!= NULL && j< i- 1 ) { //循环找到第i-1个节点 p= p-> next; j++ ; if ( p== NULL ) //判断输入位序是否大于链表总长度,是否合法 return false; LNode* s= ( LNode* ) malloc ( sizeof ( LNode) ) ; s-> data= e; s-> next= p-> next; p-> next= s; //最后修改第i-1个节点 return true; } 不带头节点 boolListInsert ( 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; L= s; //头指针指向新节点 return true; } LNode* p; //扫描节点 int j= 1 ; //计数器 p= L; //从第一个节点开始扫描 while ( p!= NULL && j< i- 1 ) { //循环找到第i-1个节点 p= p-> next; j++ ; } if ( p== NULL ) //i值不合法 return false; LNode* s= ( LNode* ) malloc ( sizeof ( LNode) ) ; s-> data= e; s-> next= p-> next; p-> next= s; return true; //插入成功 #指定元素后插操作 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; } 在按位序插入中,找到第i-1个节点后直接调用后插函数即可 return InsertNextNode(p,e); #前插操作 单链表只能往后找wuwuwu 只能遍历链表找到指定节点的前驱节点 时间复杂度O(n) 但其实还有另外一种方法 插入元素 boolInsertPriorNode ( LNode* p, ElemType e) { if ( p== NULL ) return false; LNode* s= ( LNode* ) malloc ( sizeof ( LNode) ) ; if ( s== NULL ) return false; s-> next= p-> next; p-> next= s; s-> data= p-> data; p-> data= e; return true; } 插入节点 boolInsertPriorNode ( LNode* p, LNode* s) { if ( p== NULL || s== NULL ) return false; s-> next= p-> next; p-> next= s; Elemtype temp= p-> data; p-> data= s-> data s-> data= temp; return true; } 也就是先后插,再调换 这种方式的时间复杂度是O(1) 这中偷天换日的操作还是很骚的 #按位序删除 boolListDelete ( LinkList& L, int i, ElemType& e) { if ( i< 1 ) return false; LNode* p; int j= 0 ; p= L; while ( p!= NULL && j< i- 1 ) { //循环找到第i-1个节点 p= p-> next; j++ ; } if ( p== NULL ) //i不合法 return false; if ( p-> next== NULL ) //i-1之后再无其它节点 return false; LNode* q= p-> next; //q指向被删除节点 e= q-> data//e返回删除节点中元素的值 p-> next= q-> next; free ( q) ; return true; } #删除指定节点 孩子们,我们依然找不到前驱节点 难道还要用头指针遍历链表吗??? 不,牢大有他的小妙招 boolDeleteNode ( LNode* p) { if ( p== NULL ) return false; LNode* q= p-> next; //令q指向*p的后继节点 p-> data= p-> next-> data; //和后继节点交换数据域 p-> next= q-> next; //p指向q的后继 free ( q) ; //终于删除了原本的p return true; } 那如果要删除的指定节点是最后一个节点呢? #按位序查找 //按位查找,返回第 i 个元素(带头结点) LNode* GetElem ( LinkList L, int i) { if ( i< 0 ) return NULL ; LNode* p; //指针p指向当前扫描到的结点 int j= 0 ; //当前p指向的是第几个结点 p= L; //L指向头结点,头结点是第0个结点(不存数据) while ( p!= NULL && j< i) { //循环找到第 i 个结点 p= p-> next; j++ ; } return p; } #按值查找 //按值查找,找到数据域==e 的结点 LNode* LocateElem ( LinkList L, ElemType e) { LNode* p= L-> next; //从第1个结点开始查找数据域为e的结点 while ( p!= NULL && p-> data!= e) p= p-> next; return p; //找到后返回该结点指针,否则返回NULL } #求表长 //求表的长度(带头结点) int Length ( LinkList L) { int len= 0 ; //统计表长 LNode* p= L; while ( p-> next!= NULL ) { p= p-> next; len++ ; } return len; } #尾插法建立单链表 LinkList List_TailInsert(LinkList &L){ //正向建立单链表 int x; //设ElemType为整型 L=(LinkList)malloc(sizeof(LNode)); //建立头结点 LNode *s,*r=L; //r为表尾指针 scanf("%d",&x); //输入结点的值 while(x!=9999){ //输入9999表示结束 s=(LNode *)malloc(sizeof(LNode)); s->data=x; r->next=s; r=s; //r指向新的表尾结点 scanf("%d",&x); } r->next=NULL; //尾结点指针置空 return L; }#头插法建立单链表 LinkListList_HeadInsert ( LinkList& L) { //逆向建立单链表 LNode* s; int x; L= ( LinkList) malloc ( sizeof ( LNode) ) ; //创建头结点 L-> next= NULL ; //初始为空链表,防止脏数据 scanf ( "%d" , & x) ; //输入结点的值 while ( x!= 9999 ) { //输入9999表示结束 s= ( LNode* ) malloc ( sizeof ( LNode) ) ; //创建新结点 s-> data= x; s-> next= L-> next; L-> next= s; //将新结点插入表头 scanf ( "%d" , & x) ; } return L; }