当前位置:   article > 正文

java 数据结构——java实现顺序表、单链表_java简易通讯录顺序存储代码怎么写

java简易通讯录顺序存储代码怎么写

 线性表示数据结构的一种,它是 n 个具有相同特性的 数据元素的有限序列。

顺序表

顺序表指的是用一组地址连续的存储单元存储线性表中的数据元素,称为线性表的顺序存储结构或者顺序映像。线性表采用顺序存储的方式存储就称之为顺序表。

一 . 顺序表的建立。

  1. class TestSqlist{
  2. int usedSize;//当前有效的数据元素的个数。
  3. int[] elem;//用一组地址连续的存储空间来存储顺序表的数据元素。
  4. public TestSqlist(){
  5. this(10);
  6. }
  7. public TestSqlist(int size){
  8. elem = new int[size];
  9. usedSize = 0;
  10. }
  11. }


二 . 判断顺序表是否为满。

  1. public boolean isFull(){
  2. return this.usedSize == elem.length;
  3. }

三 . 插入一个数据。

 

插入数据可以先将要插入的位置及后面的元素都向后移动一下,然后覆盖掉原来位置的元素。

 

  1. public boolean insert(int pos,int val){
  2. //判断链表是否为满
  3. if(isFull()){
  4. elem = Arrays.copyOf(elem, elem.length*2);
  5. System.out.println(elem.length);
  6. }
  7. //判断pos合法性
  8. if(pos < 0 || pos > this.usedSize ){
  9. return false;
  10. }
  11. for(int i = this.usedSize-1;i >= pos;i--){
  12. elem[i+1] = elem[i];
  13. }
  14. elem[pos] = val;
  15. this.usedSize++;
  16. return true;
  17. }


四 . 判断顺序表是否为空。

  1. public boolean isEmpty(){
  2. return this.usedSize == 0;
  3. }


五 . 删除一个数据。

用要删除的元素的后面的元素覆盖掉要删除的元素即可。最后记得要使有效长度减 1 哦。

  1. public boolean delete(int val){
  2. int i = search(val);
  3. //val不存在。
  4. if(i == -1){
  5. return false;
  6. }
  7. for(int j = i;j < this.usedSize-1;j++){
  8. elem[j] = elem[j+1];
  9. }
  10. this.usedSize--;
  11. return true;
  12. }


六 . 查找一个元素。

从头开始遍历顺序表,如果找到这个元素,返回下标即可。

  1. public int search(int key){
  2. //存在顺序表为空
  3. if(isEmpty()){
  4. return -1;
  5. }
  6. for(int i = 0;i < this.usedSize;i++){
  7. if(key == elem[i]){
  8. return i;
  9. }
  10. }
  11. return -1;
  12. }

优点

  • 无须为表示表中元素之间的逻辑关系而增加额外的存储空间
  • 可以快速地存取表中任一位置的元素

缺点

  • 插入和删除操作需要移动大量元素
  • 当线性表长度变化较大时,难以确定存储空间的容量。
  • 造成存储空间的碎片 

单链表

链式表示指的是用一组任意的存储单元存储线性表中的数据元素,线性表采用链式的存储方式称为链式表。

一 . 单链表的创建

  1. class TestLink{
  2.         class Entry{ //Entry Node
  3. int data;
  4. Entry next;//存储的是下一个节点的地址。
  5. public Entry(){
  6. data = -1;
  7. next = null;
  8. }
  9. public Entry(int val){
  10. data = val;
  11. next = null;
  12. }
  13. }
  14. public Entry head;//指向头结点的引用
  15. public TestLink(){
  16. head = new Entry();
  17. }

二 . 头插法。

插入到头结点的后面,每次先将新结点的 next 域存储头结点的下一个地址,然后将头结点的 next 域存储新结点的地址。

  1. public void insertHead(int val){
  2. Entry cur = new Entry(val);
  3. cur.next = head.next;
  4. head.next = cur;
  5. }

 

三 . 尾插法。

 

遍历链表,直到遇到某个节点的 next域 为空,将新结点的地址存入即可。

  1. public void insertTail(int val){
  2. Entry cur = new Entry(val);
  3. Entry t = head;
  4. while(t.next != null){
  5. t = t.next;
  6. }
  7. t.next = cur;
  8. }


四 . 获取链表长度。

设置一个标志 len 来记录链表的长度,遍历节点,每次 len + 1。

  1. public int getLenght(){
  2. int len = 0;
  3. Entry cur = head.next;
  4. while(cur != null){
  5. cur = cur.next;
  6.         len++;
  7. }
  8. return len;
  9. }

五 . 逆置数组。

逆置其实就是将结点的 next 存储它们原来前驱结点的地址。下图是

  1. public Entry reverse(){
  2.         Entry pre = null;//前驱
  3. Entry cur = head;
  4. Entry newhead = head;
  5. while(cur != null){
  6. Entry curnext = cur.next;
  7. if(curnext == null){
  8. newhead = cur;
  9. }
  10. cur.next = pre;
  11. pre = cur;
  12. cur = curnext;
  13. }
  14. cur = newhead;
  15. while(cur.next != null){
  16. System.out.print(cur.data+" ");
  17. cur = cur.next;
  18. }
  19. return newhead;
  20. }

 

六 . 求倒数第 k 个节点。

 

 

设置两个标志位,让fast先走k-1步,然后fast 和slow一块走,直到fast走到最后一个节点,此时slow就是倒数第k个节点。

  1. public int lastK(int k){
  2. Entry fast = head;
  3. Entry slow = head;
  4. //判断参数的合法性
  5. if(k < 0 ||k > getLength()){
  6. return -1;
  7. }
  8. //fast 先走k-1步。
  9. while(k-1 > 0){
  10. fast = fast.next;
  11. k--;
  12. }
  13. //fast 和 slow 一起走,直到fast走到最后一个节点。
  14. while(fast.next != null){
  15. fast = fast.next;
  16. slow = slow.next;
  17. }
  18. return slow.data;
  19. }

 

七 . 创造一个环。

  1. //构造一个环
  2. public void createLoop(){
  3. int len = getLength();
  4. Entry cur = head;
  5. while(cur.next != null){
  6. cur = cur.next;
  7. }
  8. cur.next = head.next.next;
  9. }

 

七 . 判断单链表是否有环。

设置一个标志位,fast 和 slow,fast 每次走两步,slow 每次走一步,由数学归纳法得到,只要slow和fast相遇,就可以证明这是一个环。

  1. public boolean isloop(){
  2. Entry slow = head.next;
  3. Entry fast = head.next;
  4. while(fast != null){
  5. fast = fast.next.next;
  6. slow = slow.next;
  7. if(fast == slow)//相遇点
  8. return true;
  9. }
  10. return false;
  11. }

 

八 . 环的入口点。

 

把slow放在头结点的位置,slow向前走x步,同时fast从相遇点开始也走x步,从图中可以看出,在入口点它们刚好相遇。

 

  1. public int enterloop(){
  2. if(!isloop()){
  3. return -1;
  4. }
  5. Entry slow = head;
  6. Entry fast = head;
  7. while(fast != null){//快引用每次走两步,慢引用每次走一步。
  8. fast = fast.next.next;
  9. slow = slow.next;
  10. if(fast == slow)//相遇点
  11. break;
  12. }
  13. slow = head;//当两个引用再次相遇的时候就是在入口点。
  14. while(slow != fast){
  15. slow = slow.next;
  16. fast = fast.next;
  17. }
  18. return slow.data;
  19. }

九 . 环的长度。

 

从图中看出环的长度为x+y, 同时从头结点到相遇点的距离也是环的x+y,所以使slow指向头结点,每次向后移动一位,同时len 加1。最后len就是环的长度。

  1. public int getLengthLoop(){
  2. int len = 0;
  3. Entry slow = head;
  4. Entry fast = head;
  5. if(!isloop()){
  6. return -1;
  7. }
  8. while(fast != null){//快引用每次走两步,慢引用每次走一步。
  9. fast = fast.next.next;
  10. slow = slow.next;
  11. if(fast == slow)//相遇点
  12.          break;
  13. }
  14. slow = head;
  15. while(slow != fast){
  16. slow = slow.next;
  17. len++;
  18. }
  19. return len;
  20. }

判断两个链表是否相交。

  1. public static boolean isCut(TestLink1 l1,TestLink1 l2){
  2. TestLink1.Entry t1 = l1.getHead();
  3. TestLink1.Entry t2 = l2.getHead();
  4. int cha;
  5. if(l1.getLength() < l2.getLength()){
  6. //使 t1 始终指向比较长的链表。
  7. t1 = l2.getHead();
  8. t2 = l1.getHead();
  9. cha = l2.getLength() - l1.getLength();
  10. }else{
  11. cha = l1.getLength() - l2.getLength();
  12. }
  13. while(cha > 0){
  14. t1 = t1.next;
  15. cha--;
  16. }
  17. while(t1 != t2 && t1!=null && t2!=null){
  18. t1 = t1.next;
  19. t2 = t2.next;
  20. }
  21. if(t1 == t2 && t1 !=null && t2 != null){
  22. System.out.println("交点:"+t1.data);
  23. return true;
  24. }else{
  25. return false;
  26. }
  27. }

合并两个链表

  1. public static TestLink1 merge(TestLink1 l1,TestLink1 l2){
  2. TestLink1.Entry newHead = null;
  3. TestLink1.Entry p1 = l1.getHead().next;
  4. TestLink1.Entry p2 = l2.getHead().next;
  5. TestLink1.Entry newtmpHead = null;
  6. if(p1.data < p2.data){
  7. newHead = l1.getHead();
  8. }else{
  9. newHead = l2.getHead();
  10. }
  11. newtmpHead = newHead;
  12. while(p1 != null && p2 != null){
  13. if(p1.data < p2.data){
  14. newtmpHead.next = p1;
  15. p1 = p1.next;
  16. }else if(p1.data > p2.data){
  17. newtmpHead.next = p2;
  18. p2 = p2.next;
  19. }else{
  20. newtmpHead.next = p1;
  21. p1 = p1.next;
  22. p2 = p2.next;
  23. }
  24. newtmpHead = newtmpHead.next;
  25. }
  26. if(p1 != null){
  27. newtmpHead.next = p1;
  28. }else{
  29. newtmpHead.next = p2;
  30. }
  31. return new TestLink1(newHead);
  32. }

单链表和顺序表的比较

存储分配方式

  • 顺序存储结构用一段连续的存储单元依次存储线性表的数据元素
  • 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素

时间性能

查找

  • 顺序存储结构O(1)
  • 链式存储结构O(n)

插入和删除

  • 顺序存储结构需要平均移动表长一半的元素,时间为O(n)
  • 单链表在找出某位置的指针后,插入和删除仅为O(1)

空间性能

  • 顺序存储结构需要预分配存储空间,分大了浪费,分小了易发生上溢
  • 单链表不需要分配存储空间,元素个数也不受限制
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/798802
推荐阅读
相关标签
  

闽ICP备14008679号