顺序表的基本操作

1、顺序表的存储结构(定义类的成员变量)

//顺序表的初始化
public SequenceList<T>{
     final int defaultSize=10;//顺序表中一维数组的初始容量
    T[]listArray;//存储元素的数组
    int length;//当前元素的实际个数
//(1)顺序表的初始化:创建一个空的顺序线性表,即给成员变量赋初值
public SequenceList(int n){
    if(n<0){
        System.out.println("error!")
        System.exit(1);
        this.listArray=(T[])new Object[n];//创建容量为n的数组
        this.length=0;//存储的元素个数为0
    }
}
public SequenceList<T>{  //创建默认容量的空顺序表
    T[]listArray=(T[])new Object[defaultSize];
    this.length=0;
    }
}

(2)插入操作(在第pos个位置插入元素obj)

步骤:①插入元素合法性判断(1<=pos<=this.length+1)

②是否需要追加空间

③An-Apos后移一个位置(下标为pos-1)

④表长加1

操作特点:插入位置后面的元素均需要后移一个位置

public boolean add(T obj,int pos){//在顺序表的第pos个位置之前插入新的数据e,pos的合法值为1-ListLength(l)+1,返回true,若i值不合法,返回false;
if(pos<1||pos>this.length+1){ //pos代表的是元素的位置,不是元素的下标索引
    System.out.println("pos值不合法");
    return false;
    }
}

  if(this.length==this.listArray.length)  { //当前存储空间已满,增加分配
//如果当前存储的元素个数等于数组的长度,则需要扩容
       T[] p= (T[])new Object[this.length * 2];
	     for(int i=0; i<this.length; i++)       
		p[i] = this.listArray[i];  //移动元素至新数组中
          this.listArray=p;
  } //end if

 for(int i=this.length-1; i>=pos-1; i--) 
//位置pos(下标pos-1)之后的元素均后移一个位置
     this.listArray[i+1] = this.listArray[i];
 this.listArray[pos-1]= obj; //obj放入第pos个单元(下标pos-1)
 this.length++; //表长加1
 return true;
}

时间复杂度分析:

l 基本操作:移动元素
l 基本操作至少执行次数: 0 次(在表尾插入时)
l 基本操作至多执行次数: n 次(在表首插入时)
l 基本操作平均执行次数:( n+(n-1)+......+0 ) / ( n+1 ) =n/2
l 时间复杂度: O(n)

(3)删除操作

步骤:判断删除位置pos合法性(1<= pos <= this.length)

将ai赋值给x

apos+1---an向前移动一个位置

表长减1

返回x

操作特点:删除位置之后的元素均需前移一个位置

public T remove(int pos)
{	//在顺序表中删除第pos个元素并返回其值,pos的合法值为1<=pos<=this.length
	if(length==0){ //空表
system.out.println("顺序表为空,无法执行删除操作");
return null; }
if(pos<1||pos>this.length)  //pos值不合法,返回null
system.out.println("pos值不合法");
return null; }
	T x = this.listArray[pos-1];
  	for(int i=pos; i<this.length; i++)
		this. listArray[i-1] = this. listArray[i]; //被删除元素之后的元素向前移一个位置
	this.length--; 	//表长减1
	return x;
} //ListDelete_Sq

基本操作:元素移动

最好情况下移动元素的次数:0次(删除表尾元素时)

最坏情况下移动元素的次数:n-1次(删除表首元素时)

平均移动元素的次数:

时间复杂度:O(n)

(4)查找操作(查找和元素obj相等的元素,返回其位序,若不存在返回0)

public int find(T obj)
{ //查找第1个与obj相等的元素的位序,返回其位序,若不存在则返回0。
		for(i=0;i<this.length;i++) 
		    if(obj.equals(this.listArray[i]) ) 
				return i+1;
		return 0;  //未查找到指定元素
} //find

(5)取值(获取顺序表第pos个位置的元素)

public T get (int  pos)
{ //返回第pos个元素,若pos<1或pos>this.length,返回null
 	if(pos<1||pos>this.length) {
	     System.out.println("pos值不合法")	;
	     return null; }  //i值不合法,返回null
 	return this.listArray[pos-1];//将第pos个元素返回,其下标为pos-1
}

(6)修改第pos个位置的元素值

public boolean set( T obj, int pos)
{//将第pos个元素设置为obj,1<=pos<=this.length
	if(pos<1 || pos>this.length)   //位序不合法
	  return false;
	this. listArray[pos-1] = obj;
          return true;
}

(7)求表长
public int size()
{	return this.length;
}
(8)判空
public boolean isEmpty()
{	 return this.length==0;
}
(9)遍历
public void  nextOrder()
{	for(int i=0;i<this.length; i++)
         System.out.print(this.listArray[i]+"  "); 
  System.out.println(); 
}
(10) 清空表
public void clear()
{	this.length=0;
}

›主程序类

public class Test3{
public static void main(String[] args){ 
//创建一个能容纳5个元素的整型顺序表L
SequenceList<Integer> L=new SequenceList<Integer>(5);
int status,e,i;
int []a={23,56,12,49,35};
for(i=0;i<a.length;i++)
L.add(a[i], i+1);  //将数组a中各个元素插入顺序表中
System.out.println("顺序表中的数据元素为:");
L.nextOrder();
L.add(30,4):  //在第4个位置插入数据元素30
System.out.printn("执行插入操作后顺序表中的数据元素为:");
L.nextOrder(); 
e=L.remove(5);  //删除第5个元素
System.out.println("执行删除操作后顺序表中的数据元素为:");
L.nextOrder();
i=L.find(12);  //在顺序表L中查找元素12的位置
System.ou.println("元素 12 在顺序表中的位置为:"+i);
}
}

线性表的链式表示和实现

线性表的链式表示

链式存储结构特点:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以连续,也可以不连续)。
单链表可 由头指针唯一确定,头指针 指向链表中第一个结点 。
首元结点是存储第一个元素的结点。
若要访问数据元素 ai , 须从头指针出发, 顺着指针域逐个结点访问,直至第 i 个结点。
因此,线性表的链式存储结构 只适合顺序访问,不支持直接访问。
线性链表也即单链表,含有一个指针域。

两种形式:
l 不带头结点 :头指针指向首元结点
l 带头结点 :头指针指向头结点,头结点的地址域指示首元结点

头结点:首元结点之前附设的一个结点,数据域内可什么都不存,头结点不计入链表长度

单链表的结点类定义

public class Node<T>{
T data;   //数据域
Node<T> next;  //指针域
public Node(T data){
	 this(data, null);
 }
public Node(){		 
	this(null, null);
 }
public Node(T data, Node<T> next)
{
	this.data = data; 
	this.next = next;
}
public String toString()
{	return this.data.toString();
    }
}

单链表的实现

public class LinkList<T>{		//单链表类
		Node<T> head;	//成员变量,头指针
		int length;	//表长,可无该成员,后面的算法都针对无length的链表
	//单链表的初始化
	public LinkList() //不带头结点的单链表构造方法
	{	 head = null;  //创建空链表
	}
	public LinkList() //带头结点的单链表构造方法
	{
		head = new Node<T>(); //创建空链表
	}

注意:一个链表只能选一种形式,带头结点或不带头结点,以上两个构造方法只在程序中写一个即可。

链表算法练习

链表

import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = Integer.valueOf(sc.nextLine().trim());
        for (int i = 0; i < n; i++) {
            String [] operator=sc.nextLine().split(" ");
            if ("insert".equals(operator[0])) {
                insert(Integer.valueOf(operator[1]), Integer.valueOf(operator[2]));
            } else {
                delete (Integer.valueOf(operator[1]));
            }
        }
        ListNode node = head;
        if (node.next == null) {
            System.out.println("NULL");
            return;
        }
        while (node.next != null) {
            System.out.print(node.next.val + " ");
            node = node.next;
        }
    }
    public static class ListNode {
        public int val;
        public ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }
    public static ListNode head = new ListNode(-1);
    public static void insert(int x, int y) {
        ListNode newNode = new ListNode(y);
        ListNode node = head;
        int sign = 0;
        while (null != node.next) {
            if (node.next.val == x) {
                newNode.next = node.next;
                node.next = newNode;
                sign = 1;
                break;
            }
            node = node.next;
        }
        if (sign == 0) {
            node.next = newNode;
        }
    }
    public static void delete (int x) {
        ListNode node = head;
        while (null != node.next) {
            if (node.next.val == x) {
                node.next = node.next.next;
                break;
            }
            node = node.next;
        }
    }
}

个人感觉这道题比较简单,涉及到一些链表的基本操作,查找、删除、添加等。但是值得注意的是关于数据的输入。 int n = Integer.valueOf(sc.nextLine().trim());

  • nextLine()方法读取输入中的一整行文本,包括所有字符,直到遇到换行符。然后,你可以使用trim()方法去除字符串两端的空白字符,并通过Integer.valueOf()Integer.parseInt()尝试将其转换为整数。这种方法更适合处理用户可能输入的复杂文本数据。
  • nextInt()方法更适用于需要用户输入单个整数的场景,并且你希望程序在读取到非整数时能够立即报错。
  • nextLine()方法提供了更大的灵活性,因为它允许你读取一整行文本,然后可以根据需要对这部分文本进行各种处理,包括转换为整数、分割成多个部分、进行字符串操作等。
  • String [] operator=sc.nextLine().split(" ");字符串将在每个空格处被拆分。
  • 拆分的结果是一个字符串数组,其中包含了被空格分隔的所有子字符串。

反转链表

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param head ListNode类
     * @return ListNode类
     */
    public ListNode ReverseList (ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            //保存的是cur的下一个值
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;

    }
}

head是头节点,首先创建了两个节点pre前驱节点和cur代表当前节点。让当前节点初始化为head头节点;pre初始化为null。因为当反转结束时,head节点会变成尾节点,而尾节点的指针指向null。循环判断的条件是当前节点为null,cur为最后一个节点时,遍历结束。先保存一下cur的下一个节点,避免反转指针之后找不到,让当前的前驱节点为cur的下一个节点,,再移动cur和pre。注意:先移动pre再移动cur

相关推荐
IU宝19 分钟前
vector的使用,以及部分功能的模拟实现(C++)
开发语言·c++
小熊科研路(同名GZH)36 分钟前
【Matlab高端绘图SCI绘图模板】第05期 绘制高阶折线图
开发语言·matlab·信息可视化
&白帝&40 分钟前
JAVA JDK7时间相关类
java·开发语言·python
2301_8187320643 分钟前
用layui表单,前端页面的样式正常显示,但是表格内无数据显示(数据库连接和获取数据无问题)——已经解决
java·前端·javascript·前端框架·layui·intellij idea
geovindu43 分钟前
Qt Designer and Python: Build Your GUI
开发语言·qt
Xiao Xiangζั͡ޓއއ44 分钟前
程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图<1>
c语言·开发语言·程序人生·学习方法·改行学it
狄加山6751 小时前
系统编程(线程互斥)
java·开发语言
星迹日1 小时前
数据结构:二叉树—面试题(二)
java·数据结构·笔记·二叉树·面试题
组合缺一1 小时前
solon-flow 你好世界!
java·solon·oneflow
HHhha.1 小时前
JVM深入学习(二)
java·jvm