1.单向链表
6.链表的查找
在链表中找到指定的第一个元素
- 沿用遍历思想,每次访问一个节点元素判断是否为要找的节点
- 符合条件返回该节点地址
- 到最后没有找到符号条件的节NULL
linknode *find_linklist(linknode *phead, datatype tmpdata) { linknode *ptmpnode = NULL; ptmpnode = phead->pnext; while(ptmpnode != NULL) { if(ptmpnode->data == tmpdata) { return ptmpnode; } else { ptmpnode = ptmpnode->pnext; } } return NULL; }
7.链表的修改
沿用遍历思想,找到需要修改的节点
/*更换链表老元素为新元素*/ int update_linklist(linknode *phead, datatype olddata, datatype newdata) { linknode *ptmpnode = phead->pnext; while(ptmpnode != NULL) { if(ptmpnode->data == olddata) { ptmpnode->data = newdata; ptmpnode = ptmpnode->pnext; } else { ptmpnode = ptmpnode->pnext; } } return 0; }
8.尾插法
在链表结尾插入一个元素
- 申请节点空间
- 将数据存放到节点中
- 将节点中地址赋值为NULL
- 找到最后一个节点
- 最后一个节点的pnext赋值为新申请节点
int insert_tail_linklist(linknode *phead, datatype tmpdata) { linknode *ptmpnode = NULL; linknode *pnewnode = NULL; ptmpnode = phead; //从空白节点开始找 pnewnode = malloc(sizeof(linknode)); if(NULL == pnewnode) { perror("fail to malloc"); return -1; } while(ptmpnode->pnext != NULL) { ptmpnode = ptmpnode->pnext; } pnewnode->data = tmpdata; pnewnode->pnext = NULL; ptmpnode->pnext = pnewnode; return 0; }
9.链表的销毁
- 定义两个指针pfreenode和ptmpnode都指向头结点
- ptmpnode向后走
- 再释放pfreenode指向的节点
- 再将pfreenode指向ptmpnode指向的空间
void destroy_linklist(linknode **pphead) { linknode *ptmpnode = NULL; linknode *pfreenode = NULL; pfreenode = *pphead; ptmpnode = *pphead; while(ptmpnode != NULL) { ptmpnode = ptmpnode->pnext; free(pfreenode); pfreenode = ptmpnode; } *pphead = NULL; return; }
10.查找链表的中间节点
- 快指针每次走2步,慢指针每次走1步
- 快指针走到末尾,慢指针走到中间
linknode *find_midnode(linknode *phead) { linknode *pfast = NULL; linknode *pslow = NULL; pfast = pslow = phead->pnext; while(pfast != NULL) { pfast = pfast->pnext; if(pfast == NULL) { break; } pfast = pfast->pnext; if(pfast == NULL) { break; } pslow = pslow->pnext; } return pslow; }
11.查找链表倒数第k个节点
- 快指针先走k步
- 慢指针和快指针每次走一步
- 快指针到达末尾,慢指针少走k步,即倒数第k个元素
/*查找链表倒数第k个节点*/ linknode *find_last_kth_node(linknode *phead, int k) { int i = 0; linknode *pfast = NULL; linknode *pslow = NULL; pfast = phead->pnext; pslow = phead->pnext; for(i = 0; i < k && pfast != NULL; i++) { pfast = pfast->pnext; } if(pfast == NULL) { return NULL; } while(pfast != NULL) { pfast = pfast->pnext; pslow = pslow->pnext; } return pslow; }
12.不知道头节点地址,如何删除链表中间节点
- 将指针指向的下一个节点的值覆盖当前节点的值
- 删除下一个节点
void delete_linknode(linknode *ptmpnode) { linknode *pnextnode = NULL; pnextnode = ptmpnode->pnext; ptmpnode->data = pnextnode->data; ptmpnode->pnext = pnextnode->pnext; free(pnextnode); return; }
13.链表的倒置
将链表所以元素倒置
- 将原链表断开
- 将所有的元素依次使用头插法插入
void reverse_linklist(linknode *phead) { linknode *ptmpnode = NULL; linknode *pinsertnode = NULL; //将链表从头结点断开 ptmpnode = phead->pnext; phead->pnext = NULL; //依次将所有元素使用头插法插入链表 while(ptmpnode != NULL) { pinsertnode = ptmpnode; ptmpnode = ptmpnode->pnext; pinsertnode->pnext = phead->pnext; phead->pnext = pinsertnode; } return; }
14.链表的排序
冒号排序
- 采用冒号排序思想,定义两个指针,相邻两个元素比较
- 指针循环向后走,直到ptmnode2为NULL,即等于pend,循环停止
- pend赋值为ptmpnode1的节点地址
- 下一轮就可以少比一次
void bubble_sort_linklist(linknode *phead) { linknode *ptmpnode1 = NULL; linknode *ptmpnode2 = NULL; linknode *pend = NULL; datatype tmpdata; if(NULL == phead->pnext || NULL == phead->pnext->pnext) { return; } while(1) { ptmpnode1 = phead->pnext; ptmpnode2 = phead->pnext->pnext; if(ptmpnode2 == pend) { break; } while(ptmpnode2 != pend) { if(ptmpnode1->data > ptmpnode2->data) { tmpdata = ptmpnode1->data; ptmpnode1->data = ptmpnode2->data; ptmpnode2->data = tmpdata; } ptmpnode1 = ptmpnode1->pnext; ptmpnode2 = ptmpnode2->pnext; } pend = ptmpnode1; } return; }
选择排序
- pswapnode指向要交换的节点
- pminnode假设的最小值
- ptmpnode和后续节点比较
void select_sort_linklist(linknode *phead) { linknode *pminnode = NULL; linknode *pswapnode = NULL; linknode *ptmpnode = NULL; datatype tmpdata; if(NULL == phead->pnext || NULL == phead->pnext->pnext) { return; } pswapnode = phead->pnext; while(pswapnode->pnext != NULL) { pminnode = pswapnode; ptmpnode = pswapnode->pnext; while(ptmpnode != NULL) { if(ptmpnode->data < pminnode->data) { pminnode = ptmpnode; } ptmpnode = ptmpnode->pnext; } if(pminnode != pswapnode) { tmpdata = pminnode->data; pminnode->data = pswapnode->data; pswapnode->data = tmpdata; } pswapnode = pswapnode->pnext; } return; }
15.判断链表是否有环
- 判断链表是否有环
- 计算环长
- 找到环的入口位置
判断是否有环
- 定义两个指针:快指针(每次2步)和慢指针(每次走1步)
- 快指针-慢指针 == 环长即相遇, 快指针和慢指针相等即为链表有环
计算环长
- 定义一个指针从环相遇开始走一圈,知道走到该节点为止
- 每走一个节点计数,最终得到环长
获得环的入口位置
- 定义一个指针,从相遇点开始每次走一步,定义一个指针,从开头每次走一步
- 两个指针相遇即为环入口
2.双向链表
1.创建空链表
参考单向链表的创建
linknode *creat_empty_linlist(void) { linknode *ptmpnode = NULL; ptmpnode = malloc(sizeof(linknode)); if(NULL == ptmpnode) { perror("fail to malloc"); return NULL; } ptmpnode->pnext = NULL; ptmpnode->ppre = NULL; return ptmpnode; }