1、概念
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。相比于线性表顺序结构,链表比较方便插入和删除操作。
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必按顺序存储,链表在插入的时候可以达到O⑴的复杂度,比另一种线性表:顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表(顺序表是在计算机内存中以数组的形式保存的线性表,采用顺序存储结构的线性表简称为“ 顺序表”)相应的时间复杂度分别是O(logn)和O⑴。链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。在计算机科学中,链表作为一种基础的数据结构可以用来生成其它类型的数据结构。
链表有很多种不同的类型:单向链表,双向链表以及循环链表。链表可以在多种编程语言中实现。线性表的链式存储表示,有一个缺点就是要找一个数,必须要从头开始找起,十分麻烦。
(1)数组和链表的区别。(很简单,但是很常考,记得要回答全面)
答:C++语言中可以用数组处理一组数据类型相同的数据,但不允许动态定义数组的大小,即在使用数组之前必须确定数组的大小。而在实际应用中,用户使用数组之前有时无法准确确定数组的大小,只能将数组定义成足够大小,这样数组中有些空间可能不被使用,从而造成内存空间的浪费。链表是一种常见的数据组织形式,它采用动态分配内存的形式实现。需要时可以用new分配内存空间,不需要时用delete将已分配的空间释放,不会造成内存空间的浪费。
从逻辑结构来看:数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况,即数组的大小一旦定义就不能改变。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费;链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项)。
从内存存储来看:(静态)数组从栈中分配空间(用NEW创建的在堆中), 对于程序员方便快速,但是自由度小;链表从堆中分配空间, 自由度大但是申请管理比较麻烦.
从访问方式来看:数组在内存中是连续存储的,因此,可以利用下标索引进行随机访问;链表是链式存储结构,在访问元素的时候只能通过线性的方式由前到后顺序访问,所以访问效率比数组要低。
2、建立链表
Node节点:
private static class Node { int num; Node nextNode; public Node(int num) { this.num = num; nextNode = null; } public Node() { nextNode = null; } } static void printList(Node head) { Node temp = head.nextNode; while (temp != null) { System.out.println("node:" + temp.num); temp = temp.nextNode; } } static Node getNewList() { Node head = new Node();// head一般不存数据,方便删除操作等。 Node node1 = new Node(1); Node node2 = new Node(2); Node node3 = new Node(3); Node node4 = new Node(4); head.nextNode = node1; node1.nextNode = node2; node2.nextNode = node3; node3.nextNode = node4; printList(head); return head; }
3、链表的插入、删除
插入
static void insertNode(Node head, Node data, int index) {// 将temp插入到第index个位置 int i = 0; Node pre = head; Node temp = head.nextNode; while (temp != null) { i++; if (i == index) { pre.nextNode = data; data.nextNode = temp; break; } pre = temp; temp = temp.nextNode; } printList(head); }
删除
static void delete(Node head, int delNum) {// 删除num为delNum的节点 Node pre = head; Node temp = head.nextNode; while (temp != null) { if (temp.num == delNum) { pre.nextNode = temp.nextNode; temp.nextNode = null; temp = pre.nextNode; } else { pre = temp; temp = temp.nextNode; } } printList(head); }
static void reverse(Node head) {// 链表的反转 if (head == null || head.nextNode == null) { return; } Node firstNode = head.nextNode; Node preNode = head.nextNode; Node curNode = head.nextNode.nextNode; Node nextNode; while (curNode != null) { nextNode = curNode.nextNode; curNode.nextNode = preNode; preNode = curNode; curNode = nextNode; } firstNode.nextNode = null; head.nextNode = preNode; printList(head); }
public static void main(String[] args) { System.out.println("----------创建链表---------"); Node head = getNewList(); System.out.println("----------将data插入到第二个位置---------"); Node data = new Node(-1); insertNode(head, data, 2); System.out.println("----------删除num为-1的节点-------"); delete(head, -1); System.out.println("----------反转链表-------"); reverse(head); }
相关引用:
http://baike.baidu.com/link?url=a_O8HDsC8tCBSpA-QdULYAsSxS0XHLu62QVRfHixy_G8m-l8RMoZnOo353qwnpPo (链表)
http://baike.baidu.com/link?url=7IhCZcwnZnE-uZOc5vE3hs6Gkc_45JUREtjWOuAQQA1Tieu_nOAmPmXK4FZVBTNv (顺序表)