线性表
线性表(linear list)是n个具有相同元素的有限序列,线性表是实际中广泛使用的数据结构,常见的线性表有:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就是说是一条连续的直线,但是在物理结构上不一定是连续的,线性表在物理上存储时,通常是以数组和链式结构形式存储。
顺序表
概念: 顺序表是一段物理地址连续的存储单元依次存储的线性结构,一般情况下采用数组存储,在数组上完成增删改查。
顺序表一般可分为:
静态顺序表:使用定长数组存储。 动态顺序表:使用动态开辟的数组存储。
静态顺序表适用于已知存储数据多少的场景,如果静态定长n值过大了,空间开大了浪费,开少了不够用,相比之下动态顺序表更灵活,根据需要动态的分配大小。
话不多说,用代码带你们了解动态顺序表
import java.util.Arrays;
public class Sequenlist {
public int[] elem;
public int useSize;
public Sequenlist(){
this.elem=new int[5];
}
public boolean isFull(){
if(this.useSize==this.elem.length){
return true;
}
return false;
}
public void add(int pos,int val){
if(isFull()){
System.out.println("顺序表满了,自动进行扩容");
this.elem=Arrays.copyOf(this.elem,this.elem.length*2);
}
if(pos<0||pos>this.useSize){
System.out.println("位置非法");
return;
}
if(pos==this.useSize){
this.elem[pos]=val;
this.useSize++;
return;
}
for(int i=this.useSize-1;i>=pos;i--){
this.elem[i+1]=this.elem[i];
}
this.useSize++;
this.elem[pos]=val;
}
public void delete( int pos){
if(pos<0||pos>this.useSize){
System.out.println("位置非法");
}
for(int i=pos;i<this.useSize;i++){
this.elem[i]=this.elem[i+1];
}
this.useSize--;
}
public int search(int find){
for(int i=0;i<this.useSize;i++){
if(find==this.elem[i]){
return i;
}
}
return -1;
}
public int getpos(int pos){
if(pos<0||pos>this.useSize){
System.out.println("位置非法");
}
return this.elem[pos];
}
public int length(){
return this.useSize;
}
public void play(){
for(int i=0;i<this.useSize;i++){
System.out.print(this.elem[i]+"\t");
}
System.out.println();
}
public boolean contains(int find){
for(int i=0;i<this.useSize;i++){
if(find==this.elem[i]){
return true;
}
}
return false;
}
public void clear(){
this.useSize=0;
}
综上就是实现一个顺序表基本操作的代码了,但是有一些问题:
顺序表的头部/中间的插入删除,时间复杂度为O(n),效率有些低 增容需要扩容空间,拷贝数据,释放旧空间,会有不小的消耗 增容一般是两倍的增长,势必会有一定的空间浪费
为了解决上述问题,于是链表来了
链表
概念
链表是一种物理存储上非连续的存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序决定的
无头单向非循环链表:结构简单,一般不会单独用来存数据,实际中更多是作为其他数据结构的子结构,如哈希桶,图的邻接表等。
class Node1{
public Node1 next;
int val;
public Node1(int val){
this.val=val;
}
}
public class LinkList2 {
public Node1 head=null;
public void addFirst(int val){
Node1 node=new Node1(val);
if(this.head==null){
this.head=node;
}else{
node.next=this.head;
this.head=node;
}
}
public void addEnd(int val){
Node1 node=new Node1(val);
if(this.head==null){
this.head=node;
}else{
Node1 cur=this.head;
while(cur.next!=null){
cur=cur.next;
}
cur.next=node;
}
}
public Node1 fun(int index){
Node1 cur=this.head;
int count=0;
while(count!=index-1){
cur=cur.next;
count++;
}
return cur;
}
public void addIndex(int index,int val){
if(index<0||index>length()){
System.out.println("位置非法");
return;
}
if(index==0){
addFirst(val);
return;
}
if(index==length()){
addEnd(val);
return;
}
Node1 res=fun(index);
Node1 node=new Node1(val);
node.next=res.next;
res.next=node;
}
public int length(){
int len=0;
Node1 cur=this.head;
while(cur!=null){
cur=cur.next;
len++;
}
return len;
}
public void display(){
Node1 cur=this.head;
while(cur!=null){
System.out.print(cur.val+"\t");
cur=cur.next;
}
System.out.println();
}
public void display1(Node1 newHead){
Node1 cur=newHead;
while(cur!=null){
System.out.print(cur.val+"\t");
cur=cur.next;
}
System.out.println();
}
public boolean contains(int key){
Node1 cur=this.head;
while(cur!=null){
if(cur.val==key){
return true;
}
cur=cur.next;
}
return false;
}
public Node1 searchPrev(int key){
Node1 cur=this.head;
while (cur.next!=null){
if(cur.next.val==key){
return cur;
}
cur=cur.next;
}
return null;
}
public void remove(int key){
Node1 cur=this.head;
if(this.head.val==key){
this.head=this.head.next;
return;
}
Node1 prev=searchPrev(key);
if(prev==null){
System.out.println("没有这个值");
return;
}
prev.next=prev.next.next;
cur=cur.next;
}
public Node1 allRemove(int key){
if(this.head==null){
return null;
}
Node1 cur=this.head;
Node1 curNext=this.head.next;
if(this.head.val==key){
this.head=this.head.next;
}
while(curNext!=null){
if(curNext.val==key){
cur.next=curNext.next;
curNext=curNext.next;
}else{
cur=curNext;
curNext=curNext.next;
}
}
return cur;
}
public void clear(){
Node1 cur=this.head;
while(cur!=null){
Node1 curNext=cur.next;
cur.next=null;
cur=curNext;
}
this.head=null;
}
无头双向链表:在java集合框架中LinkedList底层实现就是无头双向循环链表
class listNode{
public int val;
public listNode next;
public listNode prev;
public listNode(int val){
this.val=val;
}
}
public class MyDoubleLinklist {
public listNode head ;
public listNode tail;
public MyDoubleLinklist(){
listNode node = new listNode(-1);
this.head = node;
}
public void addFirst(int val){
listNode node=new listNode(val);
if(this.head.next==null){
this.head.next=node;
node.prev=this.head;
this.tail=node;
return;
}
node.next=this.head.next;
this.head.next=node;
node.prev=this.head;
}
public void addEnd(int val){
listNode node=new listNode(val);
if(this.head.next==null){
this.head.next=node;
node.prev=this.head;
this.tail=node;
}else{
this.tail.next=node;
node.prev=this.tail;
this.tail=node;
}
}
public void addIndex(int index,int val){
if(index<0||index>length()){
System.out.println("位置非法");
return;
}
if(index==0){
addFirst(val);
return;
}
if(index==this.length()){
addEnd(val);
return;
}
listNode cur=findIndex(index);
listNode node=new listNode(val);
cur.prev.next=node;
node.next=cur;
node.prev=cur.prev;
cur.prev=node;
}
public listNode findIndex(int index){
listNode cur=this.head.next;
int count=0;
while(count!=index){
cur=cur.next;
count++;
}
return cur;
}
public void delete(int key){
listNode cur=this.head.next;
while(cur!=null){
if(cur.val==key){
if(this.head.next.val==key){
this.head.next=this.head.next.next;
if(this.head.next!=null){
this.head.next.prev=null;
}else{
this.tail=null;
}
}else{
if(cur.next!=null){
cur.prev.next=cur.next;
cur.next.prev=cur.prev;
}else{
cur.prev.next=cur.next;
tail=cur.prev;
}
}
}
cur=cur.next;
}
}
public void deleteAllKey(int key) {
listNode cur = this.head.next;
while (cur != null) {
if (cur.val == key) {
if (this.head.next.val == key) {
this.head.next = this.head.next.next;
if (this.head.next != null) {
this.head.next.prev = null;
} else {
this.tail = null;
}
} else {
if (cur.next != null) {
cur.prev.next = cur.next;
cur.next.prev = cur.prev;
} else {
cur.prev.next = cur.next;
tail = cur.prev;
}
}
}
cur = cur.next;
}
}
public boolean contains(int key){
listNode cur=this.head.next;
while(cur!=null){
if(cur.val==key){
return true;
}
cur=cur.next;
}
return false;
}
public void display(){
listNode cur=this.head.next;
while(cur!=null){
System.out.print(cur.val+"\t");
cur=cur.next;
}
System.out.println();
}
public int length(){
listNode cur=this.head.next;
int count=0;
while(cur!=null){
cur=cur.next;
count++;
}
return count;
}
public void clear(){
listNode cur=this.head.next;
while(cur!=null){
listNode curNext=cur.next;
cur.next=null;
cur.prev=null;
cur=curNext;
}
this.head.next=null;
this.tail=null;
}
}
总结: 顺序表和链表的区别和联系 顺序表:优点:空间连续,支持随机访问 缺点:中间或前面插入删除时间复杂度为O(n),扩容代价较大
链表:优点:任意位置的插入删除时间复杂度为O(1),没有扩容问题,插入一个开辟一个空间 缺点:以节点为单位存储,不支持随机访问
|