初识Java语言——顺序表和链表(基础知识2——查找,插入等算法)
一、顺序表
实现顺序表代码
import java.util.Arrays;
class MyArrayList{
private int useSize;
private int[]elem;
//构造方法public MyArrayList(){
this.elem=new int[6];
}
//打印顺序表public void display(){
if(this.useSize==0){
System.out.println("null");
return;
}
for(int i=0;i<this.useSize;++i){
System.out.print(this.elem[i]+" ");
}
System.out.println();
}
//在顺序表中插入元素public void insert(int pos,int key){
if(pos<0||pos>this.useSize){
System.out.println("格式不合法");
return;
}
if(this.useSize==this.elem.length){
System.out.println("顺序表已满,扩容为两倍!");
this.elem=Arrays.copyOf(this.elem,2*(this.elem.length));
}
for(int i=this.useSize-1;i>=pos;--i){
this.elem[i+1]=this.elem[i];
}
this.elem[pos]=key;
this.useSize++;
}
//尾插public void add(int key){
if(this.useSize==this.elem.length){
System.out.println("顺序表已满,扩容为两倍!");
this.elem=Arrays.copyOf(this.elem,2*(this.elem.length));
}
this.elem[this.useSize]=key;
this.useSize++;
}
//判定是否包含某个元素public boolean contains(int key){
if(this.useSize>0){
for(int i=0;i<this.useSize;++i){
if(this.elem[i]==key){
return true;
}
}
}
return false;
}
//查找某个元素对应位置public int search(int key){
if(this.useSize>0){
for(int i=0;i<this.useSize;++i){
if(this.elem[i]==key){
return i;
}
}
}
return -1;
}
//获取pos位置的元素public int getPos(int pos){
if(pos>=0&&pos<this.useSize){
return this.elem[pos];
}
return -1;
}
//给pos位置设置为valuepublic void setPos(int pos,int value){
if(pos>=0&&pos<this.useSize){
this.elem[pos]=value;
}else{
System.out.println("pos不合法");
}
}
//删除第一次出现的关键字keypublic void remove(int key){
if(this.useSize>0){
if(search(key)!=-1){
for(int i=search(key);i<this.useSize-1;++i){
this.elem[i]=this.elem[i+1];
}
this.useSize--;
System.out.println("已删除!");
}else{
System.out.println("没有找到要删除的关键字!");
}
}else{
System.out.println("顺序表为空,不需要删除!");
}
}
//获取顺序表长度public int size(){
return this.useSize;
}
//清空顺序表public void clear(){
this.useSize=0;
}
}
public class Main {
public static void main(String[] args) {
MyArrayList num=new MyArrayList();
num.insert(0,8);
num.add(9);
num.insert(1,18);
num.display();
num.remove(8);
num.display();
num.add(99);
num.display();
System.out.println(num.search(99));
System.out.println(num.contains(8));
System.out.println(num.getPos(4));
num.clear();
num.display();
}
}
运行结果如下:
二、单向链表
1.删除链表重复节点
思路:创建一个傀儡节点,比较当前节点和下一个节点的val是否相同,不相同就往傀儡节点上挂,相同就一直往后遍历,直到找到不相同的,或者链表遍历完,最终返回傀儡节点next。就相当于一个带表头的单链表。
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead==null){
return null;
}else{
ListNode newHead=new ListNode(-1);
ListNode tmp=newHead;
ListNode cur=pHead;
while(cur!=null){
if(cur.next!=null&&cur.val==cur.next.val){
while(cur.next!=null&&cur.val==cur.next.val){
cur=cur.next;
}
cur=cur.next;
}else{
tmp.next=cur;
cur=cur.next;
tmp=tmp.next;
}
}
if(newHead.next==null){
return null;
}
tmp.next=null;
return newHead.next;
}
}
}
2.编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前
思路:创建4个引用,前两个分别代表小于x的单项链表的头尾,后两个代表大于等于x的单向链表的头尾,然后比较head的val和x的大小关系,在相应的位置尾插就行了,注意head后移。还有让最后一个节点的next变为null。
public class Partition {
public ListNode partition(ListNode pHead, int x) {
ListNode Ls=null;
ListNode Le=null;
ListNode Hs=null;
ListNode He=null;
if(pHead==null){
return null;
}else{
ListNode cur=pHead;
while(cur!=null){
if(cur.val<x){
if(Ls==null){
Le=Ls=cur;
}else{
Le.next=cur;
Le=Le.next;
}
}else{
if(Hs==null){
Hs=He=cur;
}else{
He.next=cur;
He=He.next;
}
}
cur=cur.next;
}
if(Ls==null){
return Hs;
}else{
if(He!=null){
He.next=null;
}
Le.next=Hs;
return Ls;
}
}
}
}
3.合并两个有序链表
思路:创建一个傀儡节点,让两个链表的head.val进行比较,小的就往傀儡节点上插,并将对应的头引用后移,直到其中链表有一个或都遍历完(head为null)就停,再将没遍历完的尾插到傀儡节点所指向链表上。
public class Partition {
public ListNode partition(ListNode pHead, int x) {
ListNode Ls=null;
ListNode Le=null;
ListNode Hs=null;
ListNode He=null;
if(pHead==null){
return null;
}else{
ListNode cur=pHead;
while(cur!=null){
if(cur.val<x){
if(Ls==null){
Le=Ls=cur;
}else{
Le.next=cur;
Le=Le.next;
}
}else{
if(Hs==null){
Hs=He=cur;
}else{
He.next=cur;
He=He.next;
}
}
cur=cur.next;
}
if(Ls==null){
return Hs;
}else{
if(He!=null){
He.next=null;
}
Le.next=Hs;
return Ls;
}
}
}
}
4.输入一个链表,输出该链表中倒数第k个结点
思路:快慢指针法。定义两个引用fast和slow都指向head,fast先走k-1步,然后fast和slow同时走,当fast.next为null时,slow所指向的就是倒数第k个节点。注意,可能面临k的值大于节点个数的问题,所以要在fast走k-1步时在内部加一条判断,当fast.next为null时直接return null结束。
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(head==null||k<=0){
return null;
}
ListNode fast=head;
ListNode slow=head;
while(k>1){
if(fast.next==null){
return null;
}
fast=fast.next;
k--;
}
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
return slow;
}
}
5.返回链表的中间结点
思路:还是快慢指针,fast走两步,slow走一步,直到fast的next为null时,slow所指即为中间节点。
public boolean chkPalindrome() {
Node head=this.head;
Node slow=null;
Node fast=this.head;
Node low=this.head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
low=low.next;
}
slow=low;
Node cur=slow.next;
Node end=cur.next;
while(end!=null){
cur.next=slow;
slow=cur;
cur=end;
end=end.next;
}
cur.next=slow;
slow=cur;
while(head != slow) {
if(head.val!=slow.val){
return false;
}else{
head=head.next;
slow=slow.next;
}
}
return true;
}
6.反转一个单链表
思路:定义三个引用,一个指向当前节点的前一个节点,没有就指向null,一个指向当前节点,最后一个指向当前节点的下一个节点,我们只需要让当前节点的next指向第一个引用所指向的节点,第一个引用后移指向第二个引用所指向的节点,第二个引用后移指向最后一个引用所指向的节点,最后一个引用后移,重复上述操作,直到最后一个引用指向空。
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null){
return null;
}else{
ListNode cur=head;
ListNode per=null;
ListNode nextNode=cur.next;
while(nextNode!=null){
cur.next=per;
per=cur;
cur=nextNode;
nextNode=nextNode.next;
}
cur.next=per;//注意,nextNode为null时,cur才刚指上最后一个节点,还没完成反转,所以要加这条语句
return cur;
}
}
}
7.删除链表中等于给定值 val 的所有节点
思路:一个一个比较,头节点单独处理。
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head==null){
return null;
}else{
ListNode cur=head;
ListNode per=cur.next;
while(per!=null){
if(per.val==val){
cur.next=per.next;
} else{
cur=cur.next;
}
per=per.next;
}
if(head.val==val){
head=head.next;
}
return head;
}
}
}
三、加餐:双向链表
和单向链表类似,只不过一个节点内部有三部分,val、前驱引用(prev)、后继引用(next)。
创建一个双向链表:
class ListNode{
private int val;
private ListNode next;
private ListNode prev;
public ListNode(){
}
public ListNode(int val){
this.val=val;
}
public int getVal(){
return this.val;
}
public ListNode getNext(){
return this.next;
}
public ListNode getPrev(){
return this.prev;
}
public void setVal(int val){
this.val=val;
}
public void setNext(ListNode next){
this.next=next;
}
public void setPrev(ListNode prev){
this.prev=prev;
}
}
public class DoubleLinkList {
ListNode head;
ListNode last;
//头插public void addHead(int val){
ListNode cur=new ListNode(val);
if(this.head==null){
this.head=cur;
this.last=cur;
}else{
cur.setNext(this.head);
this.head.setPrev(cur);
this.head=cur;
}
}
//尾插public void addLast(int val){
ListNode cur=new ListNode(val);
if(this.head==null){
this.head=cur;
this.last=cur;
} else{
this.last.setNext(cur);
cur.setPrev(this.last);
this.last=cur;
}
}
//打印public void display(){
ListNode cur=this.head;
while(cur!=null){
System.out.print(cur.getVal()+"->");
cur=cur.getNext();
}
System.out.println();
}
}
//Main
public class Main {
public static void main(String[] args) {
DoubleLinkList head=new DoubleLinkList();
head.addHead(8);
head.addHead(8);
head.addHead(8);
head.addLast(6);
head.addLast(6);
head.addLast(6);
head.display();
}
}
运行结果如下:
不知不觉已经到学完链表了,一起加油吧!