数据结构之线性表
线性表
线性表的基本概念
- 对于同一个线性表,其每一个数据元素的值虽然不同,但必须具有相同的数据类型;
- 数据元素之间具有一种线性的或“一对一”的逻辑关系。
- 第一个数据元素没有前驱,这个数据元素被称为开始节点;
- 最后一个数据元素没有后继,这个数据元素被称为终端节点;
- 除了第一个和最后一个数据元素外,其他数据元素有且仅有一个前驱和一个后继。
线性表的抽象数据类型描述
基本操作如下:
- 线性表的置空操作clear():将一个已经存在的线性表置为空表。
- 线性表判空操作isEmpty():判断线性表是否为空,若为空,则返回true;否则,返回为false。
- 求线性表的长度操作length():求线性表中的数据元素的个数并返回其值。
- 取元素操作get(i):读取并返回线性表中的第i个数据元素的值。其中i的取值范围为0≤i≤length()-1。
- 插入操作insert(i,x):在线性表的第i个数据元素之前插入一个值为x的数据元素。其中i的取值范围为0≤i≤length()。当i=0时,在表头插入x;当i=length()时,在表尾插入x。
- 删除操作remove(i):删除并返回线性表中第i个数据元素。其中i的取值范围为0≤i≤length()-1。
- 查找操作indexOf(x):返回线性表中首次出现的指定的数据元素的位序号,若线性表中不包含此数据元素,则返回-1。
线性表的抽线数据类型用Java接口描述如下:
1 /** 2 * 3 * @author Accper 4 * 5 */ 6 public interface IList { 7 // 线性表置空操作 8 public void clear(); 9 10 // 判断线性表是否为空操作 11 public boolean isEmpty(); 12 13 // 获取线性表中元素的长度操作 14 public int length(); 15 16 // 获取指定位置上面的元素操作 17 public Object get(int i); 18 19 // 在指定位置上面插入元素的操作 20 public void insert(int i, Object x); 21 22 // 删除指定位置上面的元素的操作 23 public void remove(int i); 24 25 // 查找指定元素的位置首次出现的位置操作 26 public int indexOf(Object x); 27 28 // 显示线性表中的内容操作 29 public void display(); 30 }
线性表的顺序存储及实现
- 顺序表的定义
- 所谓顺序表就是顺序存储的线性表。顺序存储是用一组地址连续的存储单元依次存放线性表中各个元素的存储结构。
- 顺序表的特点:
- 在线性表中逻辑上相邻的数据元素,在物理存储上也是相邻的。
- 存储密度高,但要预先分配“足够应用”的存储空间,这可能会造成存储空间的浪费。
- 便于随机存储。
- 不便于插入和删除操作,这是因为在顺序表上进行的插入和删除操作会引起大量数据元素的移动。
- 顺序存储结构类的描述
1 /** 2 * 3 * @author Accper 4 * 5 */ 6 public class SqList implements IList { 7 // 线性表存储空间 8 private Object[] listElem; 9 // 线性表的当前长度 10 private int curLen; 11 12 // 顺序表类的构造函数,构造一个存储空间容量为maxSize的线性表 13 public SqList(int maxSize) { 14 // TODO Auto-generated constructor stub 15 curLen = 0; 16 listElem = new Object[maxSize]; 17 } 18 19 // 将一个已经存在的线性表置成空表 20 public void clear() { 21 // TODO Auto-generated method stub 22 // 置顺序表的当前长度为0 23 curLen = 0; 24 } 25 26 // 判断线性表中的数据元素的个数是否为0,若为0则返回true,否则返回false 27 public boolean isEmpty() { 28 // TODO Auto-generated method stub 29 return curLen == 0; 30 } 31 32 // 求线性表中的数据元素的个数并返回其值 33 public int length() { 34 // TODO Auto-generated method stub 35 // 返回顺序表的当前长度 36 return curLen; 37 } 38 39 // 读取到线性表中的第i个数据元素并由函数返回其值,其中i的取值范围为0≤i≤length()-1,若i不在此范围则抛出异常 40 public Object get(int i) { 41 // TODO Auto-generated method stub 42 if (i < 0 || i >= curLen) { 43 throw new RuntimeException("第" + i + "个元素不存在"); 44 } 45 return listElem[i]; 46 } 47 48 // 在线性表的第i个数据元素之前插入一个值位x的数据元素 49 public void insert(int i, Object x) { 50 // TODO Auto-generated method stub 51 // 判断表是否满了 52 if (curLen == listElem.length) { 53 throw new RuntimeException("存储空间已经满了,无法插入新的元素"); 54 } 55 // 插入的位置不合法 56 if (i < 0 || i > curLen) { 57 throw new RuntimeException("插入的位置不合法"); 58 } 59 // 必须要从最后一个元素开始依次逐个后移动,直到第i个数据元素移动完毕为止。 60 for (int j = curLen; j > i; j--) { 61 listElem[j] = listElem[j - 1]; 62 } 63 listElem[i] = x; 64 curLen++; 65 } 66 67 public void remove(int i) { 68 // TODO Auto-generated method stub 69 if (i < 0 || i > curLen - 1) { 70 throw new RuntimeException("删除的位置不合法"); 71 } 72 for (int j = i; j < curLen; j++) { 73 listElem[j] = listElem[j+1]; 74 } 75 curLen--; 76 } 77 78 // 返回线性表中首次出现指定的数据元素的位序号,若线性表中不包含此数据元素,则返回-1 79 public int indexOf(Object x) { 80 // TODO Auto-generated method stub 81 for (int i = 0; i < curLen; i++) { 82 if (listElem[i].equals(x)) { 83 return i; 84 } 85 } 86 return -1; 87 } 88 89 // 输出线性表中的数据元素 90 public void display() { 91 // TODO Auto-generated method stub 92 for (int i = 0; i < curLen; i++) { 93 System.out.print(listElem[i] + " "); 94 } 95 System.out.println(); 96 } 97 98 // 测试 99 public static void main(String[] args) { 100 SqList sqList = new SqList(10); 101 sqList.insert(0, "a"); 102 sqList.insert(1, "z"); 103 sqList.insert(2, "d"); 104 sqList.insert(3, "m"); 105 sqList.insert(4, "z"); 106 int order = sqList.indexOf("z"); 107 if (order!=-1) { 108 System.out.println("顺序表中第一次出现的值为z的数据元素的位置为:"+order); 109 }else { 110 System.out.println("顺序表中不包括z元素"); 111 } 112 } 113 }
线性表的链式存储及实现
- 结点类的描述
1 /** 2 * 3 * @author Accper 4 * 5 */ 6 public class Node { 7 // 存放结点的值 8 private Object data; 9 // 后继结点的引用 10 private Node next; 11 12 // 无参数时的构造函数 13 public Node() { 14 // TODO Auto-generated constructor stub 15 this(null, null); 16 } 17 18 // 带有一个参数时的构造函数 19 public Node(Object data) { 20 this(data, null); 21 } 22 23 // 带有两个参数时的构造函数 24 public Node(Object data, Node next) { 25 this.data = data; 26 this.next = next; 27 } 28 29 public Object getData() { 30 return data; 31 } 32 33 public void setData(Object data) { 34 this.data = data; 35 } 36 37 public Node getNext() { 38 return next; 39 } 40 41 public void setNext(Node next) { 42 this.next = next; 43 } 44 }
单链表类的描述
1 /** 2 * 3 * @author Accper 4 * 5 */ 6 public class LinkList implements IList { 7 // 单链表的头指针 8 private Node head; 9 10 // 单链表的构造函数 11 public LinkList() { 12 // TODO Auto-generated constructor stub 13 // 初始化头结点 14 head = new Node(); 15 } 16 17 public LinkList(int n, boolean Order) { 18 // 初始化头结点 19 this(); 20 if (Order) { 21 // 用尾插法顺序建立单链表 22 create1(n); 23 } else { 24 // 用头插法顺序建立单链表 25 create2(n); 26 } 27 } 28 29 // 用头插法顺序建立单链表 30 private void create2(int n) { 31 // TODO Auto-generated method stub 32 Scanner sc = new Scanner(System.in); 33 for (int i = 0; i < n; i++) { 34 insert(0, sc.next()); 35 } 36 } 37 38 // 用尾插法顺序建立单链表 39 private void create1(int n) { 40 // TODO Auto-generated method stub 41 Scanner sc = new Scanner(System.in); 42 for (int i = 0; i < n; i++) { 43 insert(length(), sc.next()); 44 } 45 } 46 47 // 将一个已经存在的带头结点的单链表置成空表 48 @Override 49 public void clear() { 50 // TODO Auto-generated method stub 51 head.setData(null); 52 head.setNext(null); 53 } 54 55 // 判断带头结点的单链表是否为空 56 @Override 57 public boolean isEmpty() { 58 // TODO Auto-generated method stub 59 return head.getNext() == null; 60 } 61 62 // 求带头结点的单链表的长度 63 @Override 64 public int length() { 65 // TODO Auto-generated method stub 66 // 初始化,p指向头结点,length为计数器 67 Node p = head.getNext(); 68 int length = 0; 69 // 从头结点开始向后查找,直到p为空 70 while (p != null) { 71 // 指向后继结点 72 p = p.getNext(); 73 // 长度加1 74 length++; 75 } 76 return length; 77 } 78 79 // 读取带头结点的单链表中的第i个结点 80 @Override 81 public Object get(int i) { 82 // TODO Auto-generated method stub 83 Node p = head.getNext(); 84 int j = 0; 85 while (p != null && j < i) { 86 p = p.getNext(); 87 j++; 88 } 89 // i小于0或者大于表长减1 90 if (j > i || p == null) { 91 throw new RuntimeException("第" + i + "个元素不存在"); 92 } 93 return p.getData(); 94 } 95 96 // 在头结点的单链表中的第i个结点之前插入一个值为x的新结点 97 @Override 98 public void insert(int i, Object x) { 99 // TODO Auto-generated method stub 100 Node p = head; 101 int j = -1; 102 // 寻找第i个结点的前驱 103 while (p != null && j < i - 1) { 104 p = p.getNext(); 105 j++; 106 } 107 if (j > i - 1 || p == null) { 108 throw new RuntimeException("插入位置不合法"); 109 } 110 Node s = new Node(x); 111 // 修改链,使新结点插入到单链表中 112 s.setNext(p.getNext()); 113 p.setNext(s); 114 } 115 116 // 删除带头结点的单链表中的第i个结点 117 @Override 118 public void remove(int i) { 119 // TODO Auto-generated method stub 120 Node p = head; 121 int j = -1; 122 while (p.getNext() != null && j < i - 1) { 123 p = p.getNext(); 124 j++; 125 } 126 if (j > i - 1 || p.getNext() == null) { 127 throw new RuntimeException("删除位置不合法"); 128 } 129 // 修改链指针,使待删除结点从单链表中脱离 130 p.setNext(p.getNext().getNext()); 131 } 132 133 // 查找指定单链表中元素的位置,若在单链表中值发回该位置,如果不在单链表中则返回-1 134 @Override 135 public int indexOf(Object x) { 136 // TODO Auto-generated method stub 137 Node p = head.getNext(); 138 int j = 0; 139 while (p != null && p.getData().equals(x)) { 140 p = p.getNext(); 141 j++; 142 } 143 if (p == null) { 144 return -1; 145 } else { 146 return j; 147 } 148 } 149 150 // 输出单链表中的所有结点 151 @Override 152 public void display() { 153 // TODO Auto-generated method stub 154 // 取出带头结点的单链表中的首结点 155 Node p = head.getNext(); 156 while (p != null) { 157 // 输出结点的值 158 System.out.print(p.getData() + " "); 159 // 取下一个结点 160 p = p.getNext(); 161 } 162 System.out.println(); 163 } 164 165 // 测试 166 public static void main(String[] args) { 167 int n = 10; 168 LinkList L = new LinkList(); 169 for (int i = 0; i < n; i++) { 170 L.insert(i, i); 171 } 172 System.out.println("请输入i的值:"); 173 int i = new Scanner(System.in).nextInt(); 174 if (0 < i && i <= n) { 175 System.out.println("第" + i + "个元素的前驱是:" + L.get(i - 1)); 176 } else { 177 System.out.println("第" + i + "个元素的直接前驱不存在"); 178 } 179 } 180 }