设为首页 加入收藏

TOP

动态单链表的传统存储方式和10种常见操作-C语言实现(二)
2014-11-23 19:37:52 来源: 作者: 【 】 浏览:37
Tags:动态 单链表 传统 存储 方式 常见 操作 语言 实现
14 //p++;显然错误,离散存储,非随机结构
15 p = p->next;//指针顺链移动,直到找到或者结束循环
16 }
17 //当找不到,则p最终指向NULL,循环结束
18 return p;//返回存储位置或NULL
19 }
复制代码
算法执行时间和value有关,时间复杂度为0(n),n表长
复制代码
1 /*
2 2、查找(按序号)算法
3 查找第i个元素,并用变量value返回值,否则返回提示,即使知道了序号,也必须使用指针顺次查访
4 */
5 void getElemByNum(LinkList L, int num, char *value)
6 {
7 int count = 1;
8 LinkList p = L->next;
9 //控制指针p指向第num个结点
10 while (p && count < num)//num若为0或者负数直接跳出循环,若超出表长则遍历完毕,跳出循环,找到了元素也跳出循环
11 {
12 p = p->next;//p指向第num个结点,count此时为num值
13 count++;
14 }
15 //如果num大于表长,则count值增加到表长度时,p恰好指向表尾结点,遍历完整个链表也找不到结点,此时再循环一次
16 //p指向null,count = 表长 + 1,循环结束,这里也隐含说明了num大于 表长 的不合法情况
17 if (!p || count > num)//说明num至少比 表长 大
18 {
19 //num <= 0或者num大于表长时,跳出while循环,来到if语句,判断不合法
20 puts("num值非法!");
21 }
22 else
23 {
24 *value = p->data;
25 printf("找到第%d个元素的值 = %c\n", num, *value);
26 }
27 }
复制代码
//时间复杂度0(n),n为表长
复制代码
1 /*
2 3、删除结点
3 删除第i个元素,并用value返回值
4 */
5
6 void deleteList(LinkList L, int i, char *value)
7 {
8 LinkList p = L;//头脑一定要清晰!这里p应该指向头结点
9 LinkList temp;
10 int j = 0;//对应着头结点的序号0
11
12 /*while (p && j < i)
13 {
14 p = p->next;此时,p指向的是i元素位置,要删除i元素,需要知道i的前驱!
15 j++;
16 }*/
17
18 while (p->next && j < i - 1)//i - 1可以保证指向其前驱 ,j=0需要注意,删除是从1-n都可以
19 {
20 p = p->next;//指向i元素前驱(i-1)
21 j++;
22 }
23 //必须想到判断合法性
24 if (!(p->next) || j > i - 1)//同样判断i的下边界,和上边界
25 {
26 puts("i值不合法!");
27 }
28 else
29 {
30 //找到了前驱p
31 temp = p->next;//temp指针指向i元素
32 //p->next = p->next->next;等价于
33 p->next = temp->next;//链表删除结点的关键逻辑
34 *value = temp->data;
35 free(temp);//释放temp指向的结点的内存空间
36 temp = NULL;
37 puts("删除成功!");
38 }
39 }
复制代码
时间复杂度,虽然没有移动任何元素,还是0(n),因为最坏时核心语句频度为n(表长)
为什么不是p?
//判断表为非空,因为不止一次删除操作!总会删空,则p还是指向的头结点!如果依然是while(p &&……),表空时,按道理函数不应该再执行核心语句,提前判断出错,但此时却还要执行循环体,循环结束才能到if(!p),而使用while(p->next && ……),表空就直接跳出循环,到if语句,提示错误。这是删除算法总是需要注意的细节,插入算法则是如果内存有限,或者是顺序的表,或者静态链表,那么总是要注意存储空间满足大小的问题
复制代码
1 /*
2 4、插入结点
3 在第i个位置之前插入结点e,换句话说就是在第i-1个位置之后插入,类似前面的删除操作思想
4 */
5 void insertList(LinkList L, int i, char value)
6 {
7 LinkList p = L;
8 LinkList s;
9 int j = 0;
10 //和删除不同,插入操作不用注意表空的情况
11 while (p && j < i - 1)
12 {
13 p = p->next;
14 j++;
15 }
16
17 if (!p || j > i - 1)//i小于1或者大于表长+1不合法
18 {
19 puts("i不合法!");
20 }
21 else
22 {
23 //先分配结点存储空间
24 s = (LinkList)malloc(sizeof(Node));
25 //依次传入插入的元素内容和修改逻辑链接
26 s->data = value;
27 //链表插入算法的关键逻辑
28 s->next = p->next;
29 p->next = s;//顺序不可颠倒,原则是指针在修改前,先保留再修改,不能先修改再保留
30 puts("插入成功!");
31 }
32 }
复制代码
插入算法时间复杂度分析:0(n),最坏情况下频度是n
/插入和删除算法,还有一个思路,就是既然需要每次都找前驱,那么为什么不弄两个指针呢?一个指向当前位置,一个紧随其后指向前,个人其实感觉是脱裤子放屁……
复制代码
1 //以删除为例
2 void deleteList(LinkList L, int i, char *value)
3 {
4 LinkList prePoint = L;//前驱指针初始化指向头结点
5 LinkList point = L->next;//当前指针初始化指向第一个结点
6 LinkList temp = NULL;
7 int j = 1;
8 //i要>0,且小于等于表长
9 while (point && j < i)//如果表非空,找到要删除的元素位置
10 {
11 point = point->next;
12 prePoint = prePoint->next;//分别顺次后移
13 j++;
14 }
15
首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C 语言中的左值和右值。以及对比.. 下一篇关于C语言中的强符号、弱符号、强..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: