时间复杂度为o(n)的算法

阜哥 2005-09-26 04:40:59
设一个结构体
typedef struct dulnode
{
elemtype data;
struct dulnode *prior;
struct dulnode *next;
int length;
}dulnode, *dulinklist;
此结构体是一个双向链表的存储结构
有一个此结构的线性表l=(a1,a2,.....an),求一个时间复杂度为哦o(n)的算法,将l改造成l=(a1,a3,a5,....a6,a4,a2)
拜托各位高手了
谢谢
...全文
482 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
wshcdr 2005-09-27
  • 打赏
  • 举报
回复
对指针的操作不需要时间么?
icansaymyabc 2005-09-27
  • 打赏
  • 举报
回复
太简单了,仅需一遍扫描即可。
定义两个指针 P1,P2。

扫描链表,把奇数位置的节点添加到 P1链表的表尾;把偶数位置的节点插入到 P2链表的表头。

把 P2 链表连接到 P1 链表的尾部。

成功!

xiaocai0001 2005-09-26
  • 打赏
  • 举报
回复
对不起
上面的代码有一个小错误
if(count % 2 == 1)
{
// ++count;
//把上面一句删除
p1 = p1->next;
}
xiaocai0001 2005-09-26
  • 打赏
  • 举报
回复
程序伪码大概是

ChainList * Change(ChainList *L)
{
ListNode *p1,p2,p3;
int count = 1;
p1=L;
p2 = p3 = NULL;
while(p1 != NULL && p1->next != NULL)
{
if(count % 2 == 1)
{
++count;
p1 = p1->next;
}
else
{
//取下该结点保存到p3
p3 = p1->next;
p1 = p3->next;
p1->prior = p3->prior;
p3->prior->next = p1;
//将p3插入p2的链表中
if(p2 == NULL)
{
p2 = p3;
p2->next = NULL;
p2->prior = NULL;
}
else
{
p3->prior = NULL;
p3->next = p2;
p2->prior = p3;
}
}
++count;
}//end while
//合并链表
p1->next = p3;
p3->prior = p1;
return L;
}
xiaocai0001 2005-09-26
  • 打赏
  • 举报
回复
上面在查找链表尾的时候有时间开销,还不是O(n)的

下面一个改进的
p1,p2, p3初始状态如下:

初始:
a1→a2→a3→a4→a5→a6→a7→a8→NULL

p1
p2 = NULL;
从p1开始遍历
如果遍历的结点编号是奇数, 跳过,指向下一位
如果是偶数,则从链表上删除该结点
插入到p2结点前,若p2 = NULL, 则用p2指向该结点
一直到p1遍历结束,再将两个链表连接起来
NinGoo 2005-09-26
  • 打赏
  • 举报
回复
楼上的方法好
xiaocai0001 2005-09-26
  • 打赏
  • 举报
回复
晕~~
格式乱七八糟了
xiaocai0001 2005-09-26
  • 打赏
  • 举报
回复
一次遍历即可

两个指针
一个指向链表头 一个指向链表尾

初始:
a1→a2→a3→a4→a5→a6→a7→a8→NULL
↑ ↑
p1 p2

开始, 用P1遍历链表
若是奇数编号结点, 跳过, 若是偶数结点, p1前进一位.则将该结点从链表上取下,插入到P2后面
循环一直到p1 = p2结束

示例:
初始:
a1→a2→a3→a4→a5→a6→a7→a8→NULL
↑ ↑
p1 p2

第二步
跳过:
a1→a2→a3→a4→a5→a6→a7→a8→NULL
↑ ↑
p1 p2

将a2结点取下 ,添加到p2后面, p1后移一位

a1→a3→a4→a5→a6→a7→a8→a2NULL
↑ ↑
p1 p2


以此类推下去
zhouhuahai 2005-09-26
  • 打赏
  • 举报
回复
用空间换时间,再创建一个双向链表,这样只要遍历两次就可以了.
第一次,把a1,a3,a5,....复制到辅助链表,
第二次,把...a6,a4,a2复制到辅助链表.
cqpp 2005-09-26
  • 打赏
  • 举报
回复
改变指针都这么有规律了,遍历一遍还不能达到要求啊?
寻开心 2005-09-26
  • 打赏
  • 举报
回复
另外一个算法,无需获得尾部指针,只需要一次遍历

p1, p2是两个指针,初始的时候指向a1和a3
然后用p2来遍历
遍历过程当中,奇数次在p1指定元素的后面插入, 并且p1指针后移动
偶数次数在p1的后面插入,不移动p1指针

初始:
a1 a2 a3 a4 a5 a6 a7 a8

p1 p2

第一次
a1 a3 a2 a4 a5 a6 a7 a8
~ ~
p1 p2

第二次
a1 a3 a4 a2 a5 a6 a7 a8
~ ~
p1 p2

第三次
a1 a3 a5 a4 a2 a6 a7 a8
~ ~
p1 p2

第四次
a1 a3 a5 a6 a4 a2 a7 a8
~~
p1 p2

第五次
a1 a3 a5 a7 a6 a4 a2 a8
~ ~
p1 p2

第六次
a1 a3 a5 a7 a8 a6 a4 a2
~ ~
p1 p2

寻开心 2005-09-26
  • 打赏
  • 举报
回复
一次或者固定几次遍历可以解决的,计算量就都可以认为是O(N)

对于一个双向链表来说,先获得它的头尾指针的位置p1, p2来表示
p2始终指向最初的链表的尾部不动,把p1不断的向后移动两位
遇到偶数位,就把对应的数据摘下来,插入在p2的后面(插入后,p2的指针还不变)
如此这般,那么a2, a4, a6...., 不断的插入在p2的后面就形成了,
... a6 a4 a2 的序列了

这里面需要注意的几个特殊点
1 a2是第一个插入到p2后面的,它的next指针和preview指针需要修改成NULL和p2
2 此后插入的节点p来说
p2->next->prior=p;
p->next=p2
p->prior = p2;
p2->next = p;
3 循环移动p1的过程当中要不断的检查,是否经过了p2, 经过了就结束了计算了

队列的尾部指针如果没有预先保留的话,那么就需要遍历一遍获取它
做前面的算法需要一次遍历,因此算法的计算量最多是O(2N)


69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧