数据结构学习笔记3(链表 下 双向链表&单链表逆转)
来源:互联网 发布:手机剪辑mp3软件 编辑:程序博客网 时间:2024/04/30 01:43
一 单链表之基数排序
书上讲的不是很清楚,而且书上建议用链表实现,我看了一段时间不知道怎么用链表实现。后来参考http://www.cnblogs.com/Braveliu/archive/2013/01/21/2870201.html和http://blog.csdn.net/feixiaoxing/article/details/6876831来对基数排序算法进行学习
但是包括维基百科和上面两个网站的内容,都不能经过测试:1负数的排序问题 2 没有用到链表,只是用到了数组 PS:书中也没有讲出到底哪里用到链表了 3在大量数据的情况下,时间复杂度不乐观。
呃,至于基数排序的实现,在排序 那里再战!
二 双向链表
双向链表与单链表在创建、验证是否空链表、使空、查找.etc方面都基本相同不同在于插入数据和删除数据,涉及到两个指针的处理。基本操作如下:
#include <stdio.h>#include <STDLIB.H>typedef Double_link_Node PtrToNode;typedef int ElementType;typedef struct Node{ PtrToNode Primer; ElementType Data; PtrToNode Next;}*Double_link_Node;bool InsertData(PtrToNode L,ElementType x,int n)//刚开始返回的是链表L的首地址,但是L的首地址不变无需返回;定义为bool变量来验证函数是否正确执行{ PtrToNode tmpCell,Position; int i; tmpCell=(PtrToNode)malloc(sizeof(struct Node)); Position=(PtrToNode)malloc(sizeof(struct Node)); Position=L; if(Position->Next==NULL) return false; for(i=0;i<n&&Position->Next!=NULL;i++) Position=Position->Next;//此处也可以倒着插入 if(i<n-1) return false;//说明链表L中含有少于n个元素 tmpCell->Data=x; tmpCell->Primer=Position; if (Position->Next!=NULL) { tmpCell->Next=Position->Next; Position->Next.Primer=tmpCell; Position->Next=tmpCell; } else//恰好插入处是最后一个元素 { tmpCell->Next=NULL; Position->Next=tmpCell; } free(tmpCell); free(Position); return true;}bool DeleteData(PtrToNode L,ElementType x){ PtrToNode tmpCell,Position; int i; tmpCell=(PtrToNode)malloc(sizeof(struct Node)); Position=(PtrToNode)malloc(sizeof(struct Node)); Position=L; if(Position->Next==NULL) return false; while(Position->Next!=NULL&&Position->Next.Data!=x) Position=Position->Next; if(Position->Next==NULL) return false;//链表中没有x if (Position->Next.Next!=NULL&&Position!=L)//三种情况:1 找到x且位于链表中间 { tmpCell=Position->Next.Next; tmpCell->Primer=Position; Position->Next=tmpCell; } else if (Position==L)// 2 x位于链表头 { tmpCell=Position->Next.Next; tmpCell->Primer=NULL; L=tmpCell; } else//3 x是链表最后一个 Position->Next=NULL; free(tmpCell); free(Position); return true; }
三 循环单向链表
顾名思义,循环单向链表就是链表最后一个元素的Next指向链表的第一个元素,在操作中有一下不同
1查找、打印、计数等操作不是以==NULL作为终结条件,而是==L 即if(P->Next==NULL)
2对于插入操作,如果原来的链表IsEmpty,需要malloc空间,然后自己指向自己(这个没想到);如果原来的链表有Node,那么修改两个指针即可。
3对于删除操作,a如果只有这么一个节点,那么删除后返回NULL;b如果删除Node是头,那么要修改头
四 单链表逆转
链表逆转是面试环境中经常遇到的一道题目,也是我们在实际开发中可能会遇到的开发需求。
如果是数组逆转,就很方便实现,麻烦点的可以新建一个同样大小的数组进行赋值然后memmove;也可以直接用一个中间变量从数组中间交换对应数据。课后习题3.12a提出一个解法也很新颖,即把链表内容存入栈中,利用栈先进后出的特点对链表进行逆转。但是需要O(N)的extra space,且需要编写栈操作的例程,不划算。3.12b的答案就是下述用三个指针的方法。
链表逆转需要用到三个指针,分别记录当前节点和前后的两个节点。也可以用递归实现。给出两个实现方法。
#include <STDLIB.H>#include <STDIO.H>typedef struct Node *PtrToNode;struct Node{ PtrToNode Next; int data;};void ListReverse(PtrToNode List1,PtrToNode P);void ListReverse1(PtrToNode List1);int main(void){ PtrToNode List1,tmpCell,P; List1=(PtrToNode)malloc(sizeof(struct Node)); P=(PtrToNode)malloc(sizeof(struct Node)); List1->Next=NULL; P=List1; int i,n; for (i=0;i<5;i++) { tmpCell=(PtrToNode)malloc(sizeof(struct Node)); tmpCell->data=10-i; tmpCell->Next=P->Next; P->Next=tmpCell; } ListReverse1(List1); P=List1->Next; for (i=0;i<5&&P!=NULL;i++) { printf("%d ",P->data); P=P->Next; } return 0;}void ListReverse1(PtrToNode List1){ PtrToNode P,P1,P2; P=List1->Next; P1=NULL;//!!这里需要对P1进行初始化为NULL;不然第一个元素的next依然指向第二个元素,会形成循环链表 while(P) { //P=P->Next; P2=P->Next; P->Next=P1; P1=P; P=P2; } List1->Next=P1;//这里到最后P是无效链表,P1为倒序链表,需要用P1赋值 P=RecursiveReverse(List1,List1);//这是下文的递归实现的调用 P=List1->Next; while(P!=NULL) { printf("%d ",P->data); P=P->Next; } //return 0;}
(1不要眼高手低,任何小的程序都可能是一次考验 2程序出bug时,一定用调试来解决问题,手算不出来;对算法的基本原理要清楚)
链表逆转的递归实现
主要参考http://www.cnblogs.com/hiber/archive/2007/04/29/732293.html。但是该文中第一种递归调用调试有误,且不能清楚看懂递归的算法逻辑;第三种方法也是一种递归,但是调试过程中也出现错误,好在作者的基本思路比较清晰,进行变通后如下:
PtrToNode RecursiveReverse(Node *head,Node *List1){ struct Node *first; struct Node *rest; struct Node *P=List1; if(!(head)) return head; first = head; rest = first->Next; if(!rest)//当first指向链表尾时递归结束 { List1->Next=first; return first; } rest=RecursiveReverse(rest,List1);//递归每一个过程都是rest = first->Next,且几层递归中first指向所有的Node /*if(rest->Next==NULL) List1->Next=rest; else rest=rest->Next;*/ if(first==P) { /*first->Next=NULL;*/ return rest; } rest->Next=first; first->Next=NULL; rest=rest->Next; return rest; /*first->Next->Next = first; first->Next = NULL; head = rest;*/}
思路简介:在rest=RecursiveReverse(rest,List1);这句话之前是进行验证的步骤,运行到first指向链表尾时候,则所有的Node都已经被遍历,满足return要求,指针不再往后移动,这里把first赋值给List1->Next,是反向链表的开始处。List1这个参数也就在这里有用,这个递归思路比较简单,List1地址传递不能讨巧。在遍历完后,每一个递归过程的first分别指向各个不同的Node,从这点来说,有点浪费内存。rest的处理就是对逆序的链表进行链接,返回rest也是为了把整个表链接起来。P的作用是检测终结条件,在first==P时候说明逆序已经完全遍历一遍,如果不结束,此时first指向的是第二个节点,再对rest->Next赋值就形成了循环链表。
first->Next=NULL;很特殊,如果没有这句话,链表也可以正常逆转到最后一个Node。但是,此时first、P、List1的地址相等,即first此时指向List1,如果这里对first->Next赋值为NULL,链表也就为空;如果不对链表的最后一个Node->Next=NULL操作,则形成一个循环链表。
- 数据结构学习笔记3(链表 下 双向链表&单链表逆转)
- 数据结构-双向链表(学习笔记)
- 数据结构学习笔记(2)---双向链表
- 数据结构学习笔记(4.线性表之双向链表)
- 数据结构学习笔记(4.线性表之双向链表)
- 数据结构学习笔记之用Java实现双向链表
- 数据结构学习笔记 --- 线性表 (双向链表、循环链表)
- 数据结构学习笔记 --- 线性表 (双向链表、循环链表)
- 数据结构学习笔记 --- 线性表 (双向链表、循环链表)
- 数据结构3(双向链表)
- 回顾数据结构(3):双向链表
- 数据结构 -- 链表&双向链表
- [链表]逆转链表
- Redis源码学习3-基本数据结构之双向链表
- Redis源码学习3-基本数据结构之双向链表
- Redis源码学习3-基本数据结构之双向链表
- 双向链表的实现---数据结构学习(三)
- 双向链表的实现---数据结构学习(三)
- 【Listener】CRS-0215:RAC中的监听资源无法启动
- lua和tolua++的安装
- cassandra命令
- 新书上架。。
- 1067. Sort with Swap(0,*) (25)
- 数据结构学习笔记3(链表 下 双向链表&单链表逆转)
- Gvim for windows中块选择的方法
- -在数据库中创建一个主键自增列的表,而且其中一个列是唯一列,不存在重名
- C/C++库 stdlib.h cstdlib
- 黑马程序员——java集合中的TreeSet
- poj 3592 Instantaneous Transference
- 大风沙打火机古交姑
- 黑马程序员——java中的多线程编程
- carrandra安装