快速寻找单链表中间元素结点

来源:互联网 发布:马云的淘宝如何赚钱 编辑:程序博客网 时间:2024/04/29 02:14

忘记什么时候做的笔试题了。记忆力差没办法。

一看到这倒题目,下意识的想到的解决方案便是首先循环遍历链表获得链表长度Len,然后再次循环遍历链表查找Len/2处的中间节点。在这种情况下,其时间复杂度由两次循环决定:O(L+L/2)=O(3L/2)。

尽管这种思路也能解决问题,但也许存在更好的方法。上次我们谈到利用双指针来寻找链表中倒数第N个元素结点,现在我们同样也可以利用双指针来查找中间节点:

设置两个指针*search,*mid,初始时,都指向头结点。其中*search的移动速度为*mid的两倍。类比物理中的匀速运动,相同时间内,*search经过的结点应该是*mid结点个数的2倍,也就说,当*search结点到达链表终点时,*mid在链表中间结点处。

下面放上代码实现:

#include<stdlib.h>#include<string.h>#include<stdio.h>typedef int elemType;typedef struct Node{//定义链接节点elemType element;Node* next;}Node;int insertLast(Node** pNode, elemType ele);//1、初始化链表,未带头结点void init(Node** pNode){*pNode = NULL;printf("------>链表初始化<------\n");}void init_n(Node** pNode){*pNode = (Node*)malloc(sizeof(Node));//产生头结点,并使pNode头指针指向头结点if (!(*pNode)){printf("头结点初始化空间失败\n");}printf("------>链表初始化<------\n");(*pNode)->next = NULL;}//1、创建链表Node* create(Node* pHead){Node* p1;//代表新节点Node * p2;//代表尾节点p1 = p2 = (Node*)malloc(sizeof(Node));//申请节点if (p1 == NULL || p2 == NULL){printf("内存空间申请失败\n");exit(0);}memset(p1, 0, sizeof(Node));printf("输入节点值(非正数结束):");scanf_s("%d", &p1->element);//输入新节点p1->next = NULL;while (p1->element > 0){if (pHead == NULL){//空节点,接入表头pHead = p1;}else{p2->next = p1;//非空表,接入尾节点}p2 = p1;//重新让p2做尾节点p1 = (Node*)malloc(sizeof(Node));if (p1 == NULL || p2 == NULL){printf("内存分配失败\n");exit(0);}memset(p1, 0, sizeof(Node));printf("输入节点值(非正数结束):");scanf_s("%d", &p1->element);p1->next = NULL;}printf("链表创建成功\n");return pHead;}//打印链表,不带头结点的情况void print(Node* pHead){if (pHead == NULL){printf("链表为空\n");}else{while (pHead != NULL){printf("%d,", pHead->element);pHead = pHead->next;}printf("\n");}}//链表长度int size(Node* pHead){int size = 0;while (pHead != NULL){size++;pHead = pHead->next;}printf("链表长度%d\n", size);return size;}//获取指定位置的元素elemType get(Node* pHead, int pos){int i = 0;if (pos < 1){printf("pos值不合法\n");return 0;}if (pHead == NULL){printf("链表为空\n");return 0;}while (pHead != NULL){++i;if (pos == i){break;}pHead = pHead->next;}if (i < pos){printf("pos值超出范围\n");return 0;}return pHead->element;}//插入头节点int insertHead(Node** pNode, elemType ele){Node* pInsert;pInsert = (Node*)malloc(sizeof(Node));pInsert->element = ele;pInsert->next = *pNode;*pNode = pInsert;//代表头节点printf("向表头插入元素:%d\n",ele);return 1;}//插入尾节点int insertLast(Node** pNode, elemType ele){Node* pInsert;Node* pHead;Node* pTmp;pHead = *pNode;pTmp = pHead;pInsert = (Node* )malloc(sizeof(Node));memset(pInsert, 0, sizeof(Node));pInsert->element = ele;while (pHead->next != NULL){pHead = pHead->next;}pHead->next = pInsert;*pNode = pTmp;printf("向表尾插入元素:%d\n",ele);return 1;}//在指定位置插入元素int insertMid(Node** pNode, int pos, elemType ele){Node* pHead;Node* nHead;pHead = *pNode;Node* pInsert;pInsert = (Node*)malloc(sizeof(Node));memset(pInsert, 0, sizeof(Node));pInsert->element = ele;int i = 0;if (pNode == NULL){printf("链表为空\n");return 0;}if (pos < 1){printf("pos值非法\n");return 0;}while (pHead != NULL){++i;if (i == pos){break;}pHead = pHead->next;}if (i < pos){printf("pos值超出范围\n");return 0;}nHead = pHead->next;//保存后一个节点pInsert->next = pHead->next;pHead->next = pInsert;printf("插入中间节点\n");return 1;}//删除指定位置元素int deleteMidEle(Node** pNode, int pos){Node* pHead;Node* de;pHead = *pNode;int i = 0;if (pNode == NULL){printf("pos值非法");return 0;}while (pHead != NULL){++i;if (i == (pos-1)){break;}pHead = pHead->next;}de = pHead->next;pHead->next=de->next;printf("删除元素成功\n");return 1;}//删除第一个节点int delHead(Node** pNode){Node* pHead = *pNode;if (pNode == NULL){printf("链表为空,删除失败\n");return 0;}if (pHead->next == NULL){//只有一个节点,设置头指针为空printf("删除头节点成功\n");pHead = NULL;*pNode = pHead;return 1;}pHead = pHead->next;//设置原先头节点的下一个节点为头节点*pNode = pHead;printf("删除头节点成功\n");return 1;}//删除尾节点int delLast(Node** pNode){Node* pHead = *pNode;Node* preDel=pHead;if (*pNode == NULL){printf("链表为空,删除失败\n");return 0;}while (pHead->next!= NULL){preDel = pHead;pHead = pHead->next;}printf("删除尾节点\n");free(pHead);preDel->next = NULL;return 1;}//一次遍历查找倒数第n个元素int getNodeFromBack(Node* pHead, int n, elemType *e){int i = 0; Node* p = pHead;while (i < n&& p->next != NULL){//查找正数第n个节点i++;p = p->next;printf("%d---%d\n", i,p->element);}if (p->next == NULL&&i < n - 1){printf("超出链表长度\n");return 0;}Node* p2 = pHead;while (p != NULL){//查找倒数第n个节点p2 = p2->next;p = p->next;}*e = p2->element;printf("倒数第%d个元素是:%d\n", n, *e);return 1;}//查找中间元素结点int getMidNode(Node* pHead, elemType *e){Node* mid,*search;mid = search = pHead;while (search->next != NULL){if (search->next->next != NULL){search = search->next->next;mid = mid->next;}else{search = search->next;}}*e = mid->element;return 1;}void main(){Node* pList=NULL;int length = 0;elemType el;init(&pList);pList = create(pList);print(pList);getMidNode(pList,&el);system("pause");}

总结:

涉及单链表优化的问题,首先要考虑是否可以用双指针解决。

0 0