之前学习了Java的一些基本的语法之后,接下来我们正式进入顺序表和链表的学习。
1.线性表
线性表是n个具有相同特性的数据元素的有限序列,但线性表在逻辑上是线性结构,也就是说是一个连续的一条直线,但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
比如:
2.顺序表
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储,在数组上完成数据的增删查改。也就是我们常说的静态存储,但此种存储所用的定长数组导致N定大了,空间开多了浪费,开少了不够用。
3.顺序表的实现
第一步:
//首先我们创建一个MyLinkedList的类
public class MyLinkedList {
public int[] elem;//定义定长数组elem
public int usedSize;//有效数据个数
public MyLinkedList(){
this.elem = new int[10];//定义方法,并定义数组空间大小为10
}
第二步:接口的实现
//打印顺序表
public void display(){
for(int i = 0;i < this.usedSize;i++){
System.out.print(this.elem[i]);
}
System.out.println();
}
//获取顺序表的有效数据长度
public int size(){
return usedSize;
}
public void add(int pos, int data) {
if (pos < 0 || pos > usedSize) {
System.out.println("pos位置不合法");
return;
}
//判断空间是否已经满了,如果满了则需要增容
if (isFull()) {
This.elem = Arrays.copyOf(this.elem, 2 * this.elem.length)
}
//前一个数据覆盖后面的数据
for (int i = usedSize - 1; i >= pos; i--) {
this.elem[i + 1] = this.elem[i];
}
this.elem[pos] = data;
this.usedSize++;
}
public boolean isFull(){
return this.usedSize == this.elem.length;//相等则返回true,不等返回false
}
// 判定是否包含某个元素
public boolean contains(int toFind) {
for(int i = 0;i<usedSize;i++){
if(this.elem[i] == toFind){
return true;
}
}
return false;
}
// 查找某个元素对应的位置,找不到返回-1
public int search(int toFind) {
for(int i = 0;i<usedSize;i++){
if(this.elem[i] == toFind){
return i;
}
}
return -1;
}
// 获取 pos 位置的元素
public int getPos(int pos) {
if (pos < 0 || pos > usedSize){
System.out.println("pos位置不合法!");
return -1;
}
if(isEmpty()){
System.out.println("顺序表为空,不能得到pos位置元素");
return -1;
}
return this.elem[pos];
}
//删除第一次出现的关键字key
public void remove(int toRemove) {
if(isEmpty()){
System.out.println("顺序表为空!");
return;
}
int index = search(toRemove); //用search查询是否有这个数字
if(index == -1){
System.out.println("没有要删除的数字!");
return;
}
for(int i = index;i < this.usedSize-1;i++){
this.elem[i]=this.elem[i+1];
}
usedSize--;
}
//将pos位置的元素设为value
public void setPos(int pos,int value){
if(pos < 0 || pos >= this.usedSize){
System.out.println("pos位置不合法");
return;
}
if(isEmpty()){
System.out.println("顺序表为空!");
return;
}
this.elem[pos] = value;
}
//清空顺序表
public void clear(){
this.usedSize = 0;
//如果数组中是引用类型,则要置为空
this.elem[usedSize] = null;
}
4.链表
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。
简单的来说,链表就是有一个一个的节点构成的,一个节点由val(数据域)和next(引用地址域)组成。
5.接口实现
第一步:首先创建一个节点的next域和val域,再创建一个链表
//ListNode代表一个节点
class ListNode{
public int val;
public ListNode next;
public ListNode(int val){
this.val = val;
}
}
public class MyLinkedList3 {
public ListNode head;//链表的头引用
public void createList(){
ListNode listNode1 = new ListNode(12);
ListNode listNode2 = new ListNode(20);
ListNode listNode3 = new ListNode(25);
ListNode listNode4 = new ListNode(30);
ListNode listNode5 = new ListNode(40);
listNode1.next = listNode2;
listNode2.next = listNode3;
listNode3.next = listNode4;
listNode4.next = listNode5;
this.head = listNode1;
}
//打印整个链表
public void display(){
ListNode cur = this.head;
while(cur != null){
System.out.print(cur.val+" ");
cur = cur.next;
}
System.out.println();
}
//打印整个链表
public void display(){
ListNode cur = this.head;
while(cur != null){ //这里必须先定义一个cur=head,并且条件也是cur!=null,如果是head,则
//返回时找不到head
System.out.print(cur.val+" ");
cur = cur.next;
}
System.out.println();
}
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
ListNode cur = this.head;
while(cur != null){
if(cur.val == key){
return true;
}
cur = cur.next;
}
return false;
}
//得到单链表的长度
public int size(){
ListNode cur = this.head;
int count = 0;
while(cur != null){
count++;
cur = cur.next;
}
return count;
}
//头插法
public void addFirst(int data){
ListNode node = new ListNode(data);//先构造一个节点node
node.next = this.head;
this.head = node;
//第二种方法
/*if(this.head == null){
this.head = node;
}else{
node.next = this.head;
this.head = node;
}*/
}
//尾插法
public void addLast(int data){
ListNode node = new ListNode(data);
if(this.head == null){
this.head = node;
}else{
ListNode cur = this.head;
while (cur.next != null){
cur = cur.next;
}
cur.next = node;
}
}
//第一步:找到index-1位置处节点的地址
public ListNode findIndex(int index){
ListNode cur = this.head;
while (index-1 != 0){
cur = cur.next;
index--;
}
return cur;
}
//第二步:任意位置插入,第一个数据节点为0号下标(上述代码为本步骤第一步)
public void addIndex(int index,int data){
if(index < 0 || index > size()){
System.out.println("index位置不合法");
return;
}
if(index==0){
addFirst(data);
return;
}
if(index==size()){
addLast(data);
return;
}
ListNode cur = this.head;
ListNode node = new ListNode(index);
node.next=cur.next;
cur.next = node;
}
//找到节点key的前一个节点
public ListNode func(int key){
ListNode cur = this.head;
while (cur.next != null) {
if (cur.next.val == key) {
return cur;
}
cur = cur.next;
}
return null;
}
//删除第一次出现关键字为key的节点(上述代码为此代码的第一步)
public void remove(int key) {
if(this.head == null){
System.out.println("链表为空,不能删除!");
return;
}
if(this.head.val == key){
this.head=this.head.next;
return;
}
ListNode cur = func( key);
if(cur == null){
System.out.println("没有你要删除的节点!")
return;
}
ListNode del = cur.next;
cur.next = del.next;
}
//删除所有值为key的节点
public ListNode removeAllKey(int key) {
if(this.head == null){
return null;
}
ListNode prev = this.head;
ListNode cur = this.head.next;
while(cur != null){
if(cur.val == key){
prev.next = cur.next;
cur = cur.next;
}else{
prev = cur;
cur = cur.next;
}
}
//最后处理头
if(this.head.val == key){
this.head=this.head.next;
}
return this.head;
}
//清空链表
public void clear(){
//粗暴做法
//this.head = null;
//温柔做法
while(this.head != null){
ListNode curNext = this.head.next;
this.head = null;
this.head = curNext;
}
}