单链表结构
2016-08-24 21:38
260 查看
链表是一种复杂的数据结构,其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表,下面将逐一介绍。
单链表:单链表有一个头节点head,指向链表在内存的首地址。链表中的每一个节点的数据类型为结构体类型(数据的结构类型,有一个数据域和指针域共同组成了这种新的数据),节点有两个成员:整型成员(实际需要保存的数据,可以是泛型)和指向下一个结构体类型节点的指针即下一个节点的地址。链表按此结构对各节点的访问需从链表的头找起,后续节点的地址由当前节点给出。无论在表中访问那一个节点,都需要从链表的头开始,顺序向后查找。链表的尾节点由于无后续节点,其指针域为空,写作为NULL。
单链表的创建过程:
1、定义一个单链表的数据结构,可以说是一种新的数据类型
2、创建一个空的链表
3、分配一个指针域为NULL,数据域不设置的头结点
4、可以进行链表的使用,加入元素,将新节点的指针域成员赋为NULL,通过循环判断指针域的值是否为NULL,来找到最后一个节点或者是第一个节点
单链表的使用过程:
1、把单链表的头结点传入
2、通过检测节点中的指针域是否非NULL,来循环数据节点中的数据域
3、找到下一个节点的地址,返回第二步
网上找的一幅图
使用部分代码
2、第二种实现方式,使用两个引用,一个头引用,一个尾引用,这样就利于添加
使用部分代码
感悟:源码中的linkList实现是基于双端链表的,也就是一个节点既有上一个节点引用也有下一个节点引用,这个思想都是一样的,源码中写的有些很复杂,源码中使用了一个 size属性,就是用来作为一个查找索引使用的,这样有利于查询
单链表:单链表有一个头节点head,指向链表在内存的首地址。链表中的每一个节点的数据类型为结构体类型(数据的结构类型,有一个数据域和指针域共同组成了这种新的数据),节点有两个成员:整型成员(实际需要保存的数据,可以是泛型)和指向下一个结构体类型节点的指针即下一个节点的地址。链表按此结构对各节点的访问需从链表的头找起,后续节点的地址由当前节点给出。无论在表中访问那一个节点,都需要从链表的头开始,顺序向后查找。链表的尾节点由于无后续节点,其指针域为空,写作为NULL。
单链表的创建过程:
1、定义一个单链表的数据结构,可以说是一种新的数据类型
2、创建一个空的链表
3、分配一个指针域为NULL,数据域不设置的头结点
4、可以进行链表的使用,加入元素,将新节点的指针域成员赋为NULL,通过循环判断指针域的值是否为NULL,来找到最后一个节点或者是第一个节点
单链表的使用过程:
1、把单链表的头结点传入
2、通过检测节点中的指针域是否非NULL,来循环数据节点中的数据域
3、找到下一个节点的地址,返回第二步
C语言单链表的形式
#include <stdio.h> #include <stdlib.h> typedef struct LNode LNode;//新数据类型 typedef struct LNode* pLNode;//指针数据类型 //1、定义结构 struct LNode{ int data; //数据域 struct LNode *next; //指针域 }; pLNode addLNode(pLNode p,int i); pLNode init(pLNode p); void show(pLNode p); int main() { pLNode p=NULL; //2、创建空表 //p=(pLNode)malloc(sizeof(LNode)); p =init(p); int i=0; for(i;i<100;i++) { p = addLNode(p, i); } show(p); } pLNode init(pLNode p) { p=(pLNode)malloc(sizeof(LNode)); p->next=NULL; return p; } pLNode addLNode(pLNode p,int i) { pLNode head = p; pLNode p1=(pLNode)malloc(sizeof(LNode)); //3、使用malloc函数进行动态内存分配 p1->next=NULL; //4、把新节点的指针域赋值为null while(p->next!=NULL){ //并找到最后一个节点或者是第一个节点 p=p->next; } p->next=p1; //5、给最后一个指针域赋值为新创建的节点 p1->data=i; //给最后一个节点赋值 return head; } void show(pLNode p) { while(p->next!=NULL) { p=p->next; printf(" %d ",p); printf(" %d\n",p->data); } }
网上找的一幅图
Java语言编写的数据结构
1、第一种实现方式,只有一个头结点和一个节点个数属性,节点内容一样,就是链表的定义方式实现public class MySigleLinkListe<E> { public static class Node<E>{ Node<E> pNext; E item; public Node(Node<E> pNext, E item) { super(); this.pNext = pNext; this.item = item; } @Override public String toString() { return "Node [item=" + item + "]"; } } public MySigleLinkListe() { super(); head=new Node<E>(null, null); //穿件头指针,java中存储方式不一样, } transient Node<E> head; //头结点 transient int size; //节点数量 public void add(E e){ addLast(e); } private void addLast(E e){ final Node<E> n=new Node<E>(null,e); //新 创建了 一个节点 Node<E> m=head; //先把节点引用赋给一个中间变量引用 if(m.pNext==null) //若果这个节点中的pNext为null,说明是头结点 m.pNext=n; //则把新节点引用赋给投头结点中的pNext属性 else{ while(m.pNext!=null){ //如果已存在节点,则开始遍历,利用pNext属性为null这一特性来查找最后一个节点, m=m.pNext; //成立,则把当前引用改为 下一个引用,继续遍历 } m.pNext=n; //直到最后一个节点,这时把新节点引用赋给最后一个节点的pNext属性 } size++;//size++ } public void show(){ if(head.pNext==null){ return ; } Node<E> m=head; while(m.pNext!=null){ m=m.pNext; System.out.println(m.item.toString()); } } //存储 个数 public int count(){ return size; } }
使用部分代码
MySigleLinkListe<String> my=new MySigleLinkListe<String>(); for (int i = 0; i < 10; i++) { my.add(i+""); } my.show(); System.out.println(my.count());
2、第二种实现方式,使用两个引用,一个头引用,一个尾引用,这样就利于添加
public class MyDoubleLinkList<E> { private static class Node<E>{ E e; //Node<E> pFirst; //头引用 Node<E> pNext; //下一个节点的引用 public Node(E e, Node<E> pNext) { super(); this.e = e; this.pNext = pNext; } } transient Node<E> head; //头结点 transient Node<E> end; //尾节点 transient int size; //节点数 public MyDoubleLinkList() { super(); head=new Node<E>(null, null); end=head; } public void add(E e){ addLinkLast(e); } private void addLinkLast(E e){ Node<E> n=new Node<E>(e, null); Node<E> m=head; if(end==head){ //头节点等于尾节点时则说明还没有子节点 m.pNext=n; //把头结点的pNext指向下一个节点 end=n; //尾节点指向新节点 }else{ end.pNext=n; //把前一次的尾节点保存为新节点 end=n; //把新节点保存为尾节点 ,这样可以不用每次插入都找尾节点,效率提升了很多, } size++; } public void show(){ Node<E> m=head; while(m.pNext!=null){ m=m.pNext; System.out.println(m.e); } } public E get(int index){ Node<E> m=head; for (int i = 0; i < index+1; i++) { m=m.pNext; } return m.e; } public int count(){ return size; } }
使用部分代码
MyDoubleLinkList<String> d=new MyDoubleLinkList<String>(); for(int j=20;j<30;j++){ d.add(j+""); } for(int i=0;i<d.count();i++){ System.out.print(d.get(i)+" "); }
感悟:源码中的linkList实现是基于双端链表的,也就是一个节点既有上一个节点引用也有下一个节点引用,这个思想都是一样的,源码中写的有些很复杂,源码中使用了一个 size属性,就是用来作为一个查找索引使用的,这样有利于查询
这是get(int index)方法的源码一部分 Node<E> node(int index) { // assert isElementIndex(index); if (index < (size >> 1)){ //这里直接就进行了 一半处理,这样查找的时间大多会缩短一半, Node<E> x = first; //如果在前一半就从头引用开始查找 for (int i = 0; i < index; i++) x = x.next; return x; } else { //后一半就从尾引用忘前找,这个实现的前提就是使用双端链表 Node<E> x = last; //,才能找到上一个引用 for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
相关文章推荐
- 数据结构之链表学习笔记
- 自行实现Map底层结构(数组+链表) --Java版
- 数据结构——将两个有序链表并为一个有序链表算法
- 数据结构之链表学习心得
- 数据结构之链表
- 数据结构之线性表——链表的链式存储(链式描述)
- 数据结构之链表
- C++异常机制的实现方式和开销分析 (大图,编译器会为每个函数增加EHDL结构,组成一个单向链表,非常著名的“内存访问违例”出错对话框就是该机制的一种体现)
- 数据结构之 栈stack 模板类(链表表示)
- 数据结构—链表-单链表应用-拆分链表
- 结构之美:查找单链表指定位置结点的数据
- 结构之美:单链表逆序
- 单链表数据存储结构(c语言实现)
- 2118数据结构实验之链表三:链表的逆置
- 数据结构实验之链表九:双向链表
- 【数据结构】单链表—求链表中间节点(只遍历一次链表)— 快慢指针
- [数据结构与算法]双向链表
- C# 数据结构 单链表反转
- 结构--实现链表的“数据类型”
- 02-线性结构1 两个有序链表序列的合并(15 分)