表结构之排序顺序表(java)

package list;

/*
 * 注意该类是继承类,要有SeqList类才可以运行成功,顺序表类可以参考我之前的一篇博客
 * 作者:蓝亚之舟
 * 时间:2018.5.1
 */
public class SortedSeqList<T extends Comparable<? super T>> extends SeqList<T> {

	/*
	 * 构造空的排序顺序表,因为构造方法的方法名要与类名一致,所以子类是不能直接继承父类的构造方法的
	 * 只能声明自己的构造方法,当然构造时可以调用父类的构造方法(通过super)
	 */
	public SortedSeqList() {
		super(); // 调用父类的构造方法SeqList,因为都是构建一个数组嘛
	}

	/*
	 * 构造固定长度的排序顺序表
	 */
	public SortedSeqList(int length) {
		super(length); // 同样是调用父类的构造方法,只不过是调用的SeqList(length)方法
	}

	/*
	 * 构造给定数组内容的排序顺序表 这里不能直接简单调用父类构造方法就完事了,因为要进行排序,不是简单插入
	 */
	public SortedSeqList(T[] values) {
		super(values.length); // 首先调用父类方法,创建固定长度的空排序顺序表
		for (int i = 0; i < values.length; i++)
			this.insert(values[i]); // 这里的插入是调用子类(也就是排序顺序表类)的插入方法,可以有序插入
	}

	/*
	 * 插入操作,而且是有序插入操作
	 */
	public int insert(T x) {
		int i = 0;
		if (this.isEmpty() || x.compareTo(this.get(size() - 1)) >= 0)
			i = this.n;
		else
			while (i < this.n && x.compareTo(this.get(i)) > 0)
				i++;
		// 上面那些语句都是为了寻找当前x要插入的位置i
		super.insert(i, x); // 这一句直接调用父类方法,在第i个元素之后上插入x
		return i;

	}

	/*
	 * 有时候可能继承来的父类方法不适用,要进行重新定义,然后抛弃, 比如说下面这这两种方法
	 */
	public void set(int i, T x) { // 排序顺序表中不能随便在任意位置更改数据

		throw new java.lang.UnsupportedOperationException("set(int i,T x)");
	}

	public int insert(int i, T x) { // 排序顺序表中不能随便在任意位置插入数据
		throw new UnsupportedOperationException("insert(int i,T x)");
	}

	/*
	 * 查找方法,顺序查找首次出现的与key相等元素,如果找到返回i(0<=i<n), 若未查找成功,则返回-1
	 */
	public int search(T key) {

		for (int i = 0; i < this.n && key.compareTo(this.get(i)) >= 0; i++) {

			if (key.compareTo(this.get(i)) == 0)
				return i; // 如果相等,就返回元素序号

		}
		return -1; // 如果上面没有返回,而在这里返回,说明未查找成功
	}

	/*
	 * 覆盖父类的删除方法,其中this.search(key)是运行时多态,因为当前类和父类都有 search方法,在两个中确定一个
	 */
	public T remove(T key) {

		return this.remove(this.search(key));
		// 这里的remove方法是重载,更改了参数(原来是i,现在是key),这里的remove是调用继承父类的remove,参数是i
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String[] str = { "aa", "bb", "cc" };
		SortedSeqList<String> list = new SortedSeqList<String>(str);
		System.out.println(list.toString());
		list.remove("aa");
		System.out.println(list.toString());

	}

}

这个类是建立在我之前的那篇SeqList上的,可以参考我之前的顺序表博客,这里我总结一下我遇到的一些知识点

1、子类继承原则

(1)子类不能继承父类的构造方法:

      因为构造方法名称要与类名一致,显然子类与父类的类名是不一致的,所以无法继承,但是可以通过super调用父类的构造方法,具体可以参考上述的代码实例

(2)子类继承的父类中的成员访问权限

     这个权限取决于父类成员声明的访问权限,即子类可以访问父类的公有(public)和保护(protected)成员(这里我想说的是,在声明变量时,不要总是设置为公有变量,当然一般新手都是不管什么变量都是一成不变的public,我一开始也是这个样子——本质上编程代码量很小,因为搞不懂三种变量类型的关系,设置成其他类型总是出现一系列问题,但是如果你想成为高级程序员,就要开始寻求转变,学会封装自己的类,这样在大型程序设计时,更加安全)

(3)子类不能删除从父类继承来的成员

     当从父类那里继承来的成员(包括变量和函数方法)不能满足子类需要时,子类不能删除它们;但是可以重定义它们,可以修改或扩充父类成员方法的功能,使父类成员能够适应子类的新需求

(4)子类重定义父类成员包括:
  • 重定义父类的成员变量,则隐藏父类的成员变量(举个例子,你在父类定义变量u=8,然后又在子类中重新定义了一下u=2,那么在子类中当你调用u时,它就是2,当然你可以通过super来调用父类的u——父类u为8)
  • 重定义父类的成员方法:如果参数相同,则覆盖(override)父类的成员方法(继承来的方法会被覆盖掉),但是返回值类型必须与父类方法赋值相容(其实本质就是重写从父类那里继承来的方法,返回值和参数都不变,仅仅是内容更改了);如果参数不相同,则重载(overload)父类的成员方法(也就是重写写一个新的方法——当然这个方法方法名和返回值都要相同,只是参数和内容不同)
  • 子类重定义时,父类成员表现为多态性,父类对象引用父类成员,子类对象引用子类成员(子类有很多继承来的方法,看似是引用父类的,其实是自身的方法,因为他已经继承过来了,在子类中调用父类方法只能通过super)

2、super的应用(感觉总是提到super,这里就详细写一下)

在子类的实例成员方法中,可以使用“super引用”访问被子类隐藏的父类同名成员变量(这里的隐藏是指,子类重新定义了一下这个变量),也可以调用被子类覆盖的父类同名成员方法——其实本质上,你就可以把super看做是父类的实例引用,然后可以通过它调用父类的成员方法与变量(注意仅限于公有和保护成员

注意:静态方法中(带有static的区块),不能使用super引用(比如main方法,如果想要调用的话,可以写一个方法函数,然后在里面调用super,然后再在main里面使用该方法)

super的三种用法:
super.xxx ;     //xxx表示名为xxx的成员变量,这里是指调用父类中的成员变量
super.xxx();   //这里是调用父类中的xxx方法
super();    //这是调用父类的初始化方法,即public 父类名();

3、子类的重载问题

上面编写代码时,我一开始对于remove方法就有些不理解


上面这段代码中,我用到了this.search(key),这是搜索元素为key的方法,返回值为i(也就是key的序号,如果存在的话),但我并没有在这个类中声明public T  remove(int i)方法啊,为什么我调用这个方法时,会用this(表示这个子类的对象实例引用)呢?

后来我查找了一下,这个类中究竟有没有这个remove方法,结果如下:


大家可以看到,当我调用list(子类)的remove方法时,它给我了两个选择:一个是remove(int i),一个是remove(String key),通过上面的代码可以看到,我在SortedSeqList类中,只定义了后者,而没有定义前者,所以说前者是继承来的,后者是我重新的定义的(重载——因为参数不同,一个是int,一个是key),所以你的程序中可能没有定义这个方法,但是可能你继承的父类方法中就有这个方法(其实在编译时,会将父类的方法给加载进来,只是这个过程你不知道,它对你是透明的)

说了这么多,不知道大家有没有明白,其实这个重载非常简单,就是继承过来了,虽然没有显示

4、多态

根据何时确定执行多态方法中的哪一个,多态分为两种情况:编译时多态运行时多态,如果在编译时能够确定执行多态方法中的哪一个,则称为编译时多态,否则称为运行时多态。

覆盖表现为父类与执行子类之间方法的多态性,编译器或运行系统,根据调用方法的实例类型是父类还是子类,来确定执行多态方法中的哪一个,父类对象调用父类方法,子类对象调用子类方法

具体多态的理解可以参考这篇:理解java的三大特性之多态(感觉写的很形象)

5、上面代码中,继承中出现的

<T extends Comparable<? super T>>

这里推荐两个好的连接:

知乎介绍

Java中如何理解<t extends="" comparable<?="" super="" t="">>(好吧这个短语总是输不进去)

6、比较对象大小的方法

一般情况下,引用数据类型没有比较大小的概念,因此,java中对于引用数据类型没有定义<,<=,>等关系运算符

约定java.lang.Comparable<T>接口的compareTo(T)的方法比较T类的对象大小,声明如下:

public interface Compareble <T> {
      int compareTo(T obj)            //比较对象大小,返回0,正、负整数,分别表示相等,大,小
}
(1)首先是字符串的比较:
                String a1 = "aaa";
		String a2 = "aaa";
		String a3 = "aaawe";
		String a4 = "aab";
		String a5 = "ac";
		String a6 = "aa";
		System.out.println("1.aaa与aaa比较:" + a1.compareTo(a2));
		System.out.println("2.aaa与aaawe比较:" + a1.compareTo(a3));
		System.out.println("3.aaa与aab比较:" + a1.compareTo(a4));
		System.out.println("4.aaa与ac比较:" + a1.compareTo(a5));
		System.out.println("5.aaa与aa比较:" + a1.compareTo(a6));

执行结果:


通过这个结果,我们可以得到以下几个结论:
  • 字符串比较的是ASCLL码值
  • 比较的时候,首先看第一位,如果第一位一样,就比较第二位,如果第二位一样,就比较第三位,直到出现一位不一样的,当这一位不一样,就让A的ASCLL值减去B的ASCLL值(以第3种情况为例,这里的A是指aaa,B是指aab,前两位位值都一样,直到第三位不一样,让a的ASCLL值减去b的ASCLL值,然后返回结果)
  • 注意这种比较,只会比较第一位出现的不同之处,比如aaa与abc进行比较的话,那么只会比较a与b(也就是第二位),第三位虽然也不一样,但是不会再进行比较,举个例子aaa与abc,aaa与aab最终结果都是一样的,都是-1(因为都是比较a与b)
  • 还有一种情况,就是当两个比较的字符串(一长一短)短的和长的前半部分相同,那么最终结果返回的是长的部分减去短的部分(长度的比较),可以参考如下代码:
		String a1 = "aaa";
		String a2 = "aaase";
		String a3 = "aaawe";
		String a4 = "aaawef";

		System.out.println("1.aaa与aaase比较:" + a1.compareTo(a2));
		System.out.println("2.aaa与aaawe比较:" + a1.compareTo(a3));
		System.out.println("3.aaa与aawef比较:" + a1.compareTo(a4));

执行结果:


aaa与aaase比较结果,aaa与aaawe比较结果是相同的,虽然两者第四位的值不一样,但是他们长度一样,都比aaa长度大2

(2)数字的比较

首先你要知道int类型不能用compare进行比较,要用integer类型才可以:


接下来是比较代码:

运行结果:


可以看出,Integer的比较比字符串比较要简单很多,因为返回值就三种情况:0(相等),-1(小于)和1(大于)


参考书籍:《数据结构(java版)》叶核亚,有不懂的,可以再看一下这本书

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值