线性表示数据结构的一种,它是 n 个具有相同特性的 数据元素的有限序列。
顺序表指的是用一组地址连续的存储单元存储线性表中的数据元素,称为线性表的顺序存储结构或者顺序映像。线性表采用顺序存储的方式存储就称之为顺序表。
class TestSqlist{
int usedSize;//当前有效的数据元素的个数。
int[] elem;//用一组地址连续的存储空间来存储顺序表的数据元素。
public TestSqlist(){
this(10);
}
public TestSqlist(int size){
elem = new int[size];
usedSize = 0;
}
}
public boolean isFull(){
return this.usedSize == elem.length;
}
插入数据可以先将要插入的位置及后面的元素都向后移动一下,然后覆盖掉原来位置的元素。
public boolean insert(int pos,int val){
//判断链表是否为满
if(isFull()){
elem = Arrays.copyOf(elem, elem.length*2);
System.out.println(elem.length);
}
//判断pos合法性
if(pos < 0 || pos > this.usedSize ){
return false;
}
for(int i = this.usedSize-1;i >= pos;i--){
elem[i+1] = elem[i];
}
elem[pos] = val;
this.usedSize++;
return true;
}
public boolean isEmpty(){
return this.usedSize == 0;
}
用要删除的元素的后面的元素覆盖掉要删除的元素即可。最后记得要使有效长度减 1 哦。
public boolean delete(int val){
int i = search(val);
//val不存在。
if(i == -1){
return false;
}
for(int j = i;j < this.usedSize-1;j++){
elem[j] = elem[j+1];
}
this.usedSize--;
return true;
}
从头开始遍历顺序表,如果找到这个元素,返回下标即可。
public int search(int key){
//存在顺序表为空
if(isEmpty()){
return -1;
}
for(int i = 0;i < this.usedSize;i++){
if(key == elem[i]){
return i;
}
}
return -1;
}
链式表示指的是用一组任意的存储单元存储线性表中的数据元素,线性表采用链式的存储方式称为链式表。
class TestLink{
class Entry{ //Entry Node
int data;
Entry next;//存储的是下一个节点的地址。
public Entry(){
data = -1;
next = null;
}
public Entry(int val){
data = val;
next = null;
}
}
public Entry head;//指向头结点的引用
public TestLink(){
head = new Entry();
}
插入到头结点的后面,每次先将新结点的 next 域存储头结点的下一个地址,然后将头结点的 next 域存储新结点的地址。
public void insertHead(int val){
Entry cur = new Entry(val);
cur.next = head.next;
head.next = cur;
}
遍历链表,直到遇到某个节点的 next域 为空,将新结点的地址存入即可。
public void insertTail(int val){
Entry cur = new Entry(val);
Entry t = head;
while(t.next != null){
t = t.next;
}
t.next = cur;
}
设置一个标志 len 来记录链表的长度,遍历节点,每次 len + 1。
public int getLenght(){
int len = 0;
Entry cur = head.next;
while(cur != null){
cur = cur.next;
len++;
}
return len;
}
逆置其实就是将结点的 next 存储它们原来前驱结点的地址。下图是
public Entry reverse(){
Entry pre = null;//前驱
Entry cur = head;
Entry newhead = head;
while(cur != null){
Entry curnext = cur.next;
if(curnext == null){
newhead = cur;
}
cur.next = pre;
pre = cur;
cur = curnext;
}
cur = newhead;
while(cur.next != null){
System.out.print(cur.data+" ");
cur = cur.next;
}
return newhead;
}
设置两个标志位,让fast先走k-1步,然后fast 和slow一块走,直到fast走到最后一个节点,此时slow就是倒数第k个节点。
public int lastK(int k){
Entry fast = head;
Entry slow = head;
//判断参数的合法性
if(k < 0 ||k > getLength()){
return -1;
}
//fast 先走k-1步。
while(k-1 > 0){
fast = fast.next;
k--;
}
//fast 和 slow 一起走,直到fast走到最后一个节点。
while(fast.next != null){
fast = fast.next;
slow = slow.next;
}
return slow.data;
}
//构造一个环
public void createLoop(){
int len = getLength();
Entry cur = head;
while(cur.next != null){
cur = cur.next;
}
cur.next = head.next.next;
}
设置一个标志位,fast 和 slow,fast 每次走两步,slow 每次走一步,由数学归纳法得到,只要slow和fast相遇,就可以证明这是一个环。
public boolean isloop(){
Entry slow = head.next;
Entry fast = head.next;
while(fast != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow)//相遇点
return true;
}
return false;
}
把slow放在头结点的位置,slow向前走x步,同时fast从相遇点开始也走x步,从图中可以看出,在入口点它们刚好相遇。
public int enterloop(){
if(!isloop()){
return -1;
}
Entry slow = head;
Entry fast = head;
while(fast != null){//快引用每次走两步,慢引用每次走一步。
fast = fast.next.next;
slow = slow.next;
if(fast == slow)//相遇点
break;
}
slow = head;//当两个引用再次相遇的时候就是在入口点。
while(slow != fast){
slow = slow.next;
fast = fast.next;
}
return slow.data;
}
从图中看出环的长度为x+y, 同时从头结点到相遇点的距离也是环的x+y,所以使slow指向头结点,每次向后移动一位,同时len 加1。最后len就是环的长度。
public int getLengthLoop(){
int len = 0;
Entry slow = head;
Entry fast = head;
if(!isloop()){
return -1;
}
while(fast != null){//快引用每次走两步,慢引用每次走一步。
fast = fast.next.next;
slow = slow.next;
if(fast == slow)//相遇点
break;
}
slow = head;
while(slow != fast){
slow = slow.next;
len++;
}
return len;
}
public static boolean isCut(TestLink1 l1,TestLink1 l2){
TestLink1.Entry t1 = l1.getHead();
TestLink1.Entry t2 = l2.getHead();
int cha;
if(l1.getLength() < l2.getLength()){
//使 t1 始终指向比较长的链表。
t1 = l2.getHead();
t2 = l1.getHead();
cha = l2.getLength() - l1.getLength();
}else{
cha = l1.getLength() - l2.getLength();
}
while(cha > 0){
t1 = t1.next;
cha--;
}
while(t1 != t2 && t1!=null && t2!=null){
t1 = t1.next;
t2 = t2.next;
}
if(t1 == t2 && t1 !=null && t2 != null){
System.out.println("交点:"+t1.data);
return true;
}else{
return false;
}
}
public static TestLink1 merge(TestLink1 l1,TestLink1 l2){
TestLink1.Entry newHead = null;
TestLink1.Entry p1 = l1.getHead().next;
TestLink1.Entry p2 = l2.getHead().next;
TestLink1.Entry newtmpHead = null;
if(p1.data < p2.data){
newHead = l1.getHead();
}else{
newHead = l2.getHead();
}
newtmpHead = newHead;
while(p1 != null && p2 != null){
if(p1.data < p2.data){
newtmpHead.next = p1;
p1 = p1.next;
}else if(p1.data > p2.data){
newtmpHead.next = p2;
p2 = p2.next;
}else{
newtmpHead.next = p1;
p1 = p1.next;
p2 = p2.next;
}
newtmpHead = newtmpHead.next;
}
if(p1 != null){
newtmpHead.next = p1;
}else{
newtmpHead.next = p2;
}
return new TestLink1(newHead);
}
查找
插入和删除
空间性能