Linux学习—数据结构(链表2)
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; }