最近寒假回來無聊想研究一下數據結構和算法。所以從頭開始又開始看起了數據結構,現在纔是剛起步所以只是淺顯的實現了一下簡單的數據結構,今天花了一天實現了線性表的順序存儲結構。首先了解一下什麼是線性表:線性表就是零個或多個數據元素的有限序列。數據元素之間具有順序關係。除了第一個數據元素和最後一個數據元素之外,其他數據元素都只有一個直接前驅和直接後繼,而第一個元素只有直接後繼沒有直接前驅,最後一個元素只有直接前驅沒有直接後繼。而且線性表中的數據元素可以是簡單類型的數據也可以是複雜的對象。線性表按存儲方式分爲兩種,一種是順序存儲結構,另一種則是鏈式存儲結構。所謂的順序存儲結構就是數據元素在內存中以連續的地址存儲,學過c的都知道就像數組一樣,內存分配一個連續的地址來存儲數據元素。在這裏鏈式存儲結構暫時還未總結準備下一個階段總結。
接下來就簡單描述我實現的線性表的順序存儲結構的案例:
此案例是用來實現線性表的順序存儲結構
1、線性表的存儲數據元素爲學生對象,學生對象只有簡單的學號和姓名(其中排序是以名字排的,爲了實現理解我的名字格式是張3這樣格式的,當然也可以改動的)
2、當線性表長度不夠時不拋出異常而是動態添加線性表的長度
3、對線性表的的主要操作有:初始化、求長度、取值、設置值、定位、插入、刪除、複製、合併、查找、排序、遍歷
學生類作爲存儲的數據元素實現了Comparable接口,用於實現排序的:
package com.yc.entity;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* 線性表的存儲數據是一個學生對象
* @author WenQu
*/
public class Student implements Comparable<Student>{
//爲了理解數據結構 數據元素的數據項只寫了兩個
private String sid;
private String sname;
public Student() {
}
public Student(String sid, String sname) {
this.sid = sid;
System.out.println("我的學號是:"+this.sid);
this.sname = sname;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((sid == null) ? 0 : sid.hashCode());
result = prime * result + ((sname == null) ? 0 : sname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (sid == null) {
if (other.sid != null)
return false;
} else if (!sid.equals(other.sid))
return false;
if (sname == null) {
if (other.sname != null)
return false;
} else if (!sname.equals(other.sname))
return false;
return true;
}
//實現comparable接口來比較學生的大小
@Override
public int compareTo(Student student) {
//如果兩個學生相等那麼就直接不交換
if(this==student){
return 0;
}else{
//截取用正則表達式截取
Pattern pattern=Pattern.compile("[^0-9]"); //模式定義找到字符串中不是0-9中的
Matcher matcher=pattern.matcher(this.getSname()); //匹配模式中的字符串
int name=Integer.parseInt(matcher.replaceAll("") ); //替換匹配到的字符串
Matcher matcher2=pattern.matcher(student.getSname());
int sname=Integer.parseInt(matcher2.replaceAll("") );
if(name>sname){
return 1;
}else{
return -1;
}
}
}
}
線性表的實現類用來存儲學生的:
package com.yc.bean;
import java.util.Arrays;
import javax.sound.midi.VoiceStatus;
import com.yc.entity.Student;
//這是用來存儲學生的一個線性表的順序存儲結構
public class StudentList {
private Student[] studentList; //線性表 表明創建的是一個線性表 數組的順序是連續的
private static final int listLength=10; //每次添加線性表的長度 靜態常量節省空間
private int dateLength=0; //記錄線性表的實際存儲數據長度
//線性表的實例化 也是其的初始化函數
public StudentList(){
}
//線性表的初始化
public void initList(){
studentList=new Student[listLength];
}
//獲得線性表的存儲數據長度
public int getDateLength(){
return dateLength;
}
//線性表獲得鏈表
public Student[] getList(){
return Arrays.copyOf(this.studentList, dateLength);
}
//獲得指定位置的數據元素
public Student getElement(int i){
//如果位置不對那麼就輸出
if(i<0||i>dateLength){
System.out.println("該位置爲不合理位置!!!!");
return null; //位置不存在返回空
}
return studentList[i-1];
}
//設定線性表的某個位置的值
public void setElement(int i,Student student){
if( !(student instanceof Student)||i<0||i>dateLength ){
//如果添加的元素不是學生類型那麼就直接返回了
return;
}
//如果設置的條件是合理的那麼就開始設置值
studentList[i-1]=student;
}
//插入一個元素 插在線性表的後面
public void insertInList(Student student){
//如果插入時長度不夠那麼就添加線性表的長度
if(dateLength>=studentList.length){
studentList=extendList();
}
//現在就可以動態的添加學生了
studentList[dateLength++]=student;
System.out.println("datelength的長度爲:"+dateLength);
}
//按照位置插入
public void insertByI(int i,Student student){
//當插入的位置不存在時就直接返回
if(i<0||i>dateLength){
return;
}
//判斷當前的數組長度是否已經滿了 如果已經滿了那麼就先擴展數組的長度在添加
if(dateLength==studentList.length){
//拓展吸線性表的長度
studentList=extendList();
}
//然後開始進行再指定位置插入元素 把指定位置後面的元素往後移動然後在插入數據
for(int j=dateLength-1;j>=i-1;j--){
studentList[j+1]=studentList[j];
}
//最後把要插入的插進去
studentList[i-1]=student;
dateLength++;
}
//刪除線性表中的某個位置的元素
public void delElement(int i){
//當位置超過元素個數的時候直接跳過
if(i<0||i>dateLength){
return;
}
//如果位置合理那麼就可以直接進行刪除
for(int j=i;j<dateLength;j++){
studentList[j-1]=studentList[j];
}
dateLength--;
}
//複製數組
public Student[] copyList(Student[] src,Student[] dest){
if(dest==null){
dest=new Student[src.length];
}
System.arraycopy(src, 0, dest, 0, src.length);
return dest;
}
//合併兩個線性表
public Student[] combineList(Student[] s1,Student[] s2){
if(s1==null&&s2==null){
return null;
}
int count=0,dis=0;
count+=s1==null?0:s1.length;
count+=s2==null?0:s1.length;
Student[] temp=new Student[count];
if(s1!=null){
//複製第一個
System.arraycopy(temp, dis, s1, 0, s1.length);
dis+=s1.length;
}
if(s2!=null){
//複製第二個
System.arraycopy(temp, dis, s2, 0, s2.length);
}
return temp;
}
//查找滿足條件的數據元素 返回null則是沒有返回對象則是找到的與模板元素相等的
public Student searchElement(Student student){
for(int i=0;i<studentList.length;i++){
if(student==studentList[i]){
return studentList[i];
}
}
return null;
}
//排序 按照關鍵字的遞減排序 使用的是冒泡排序
public void sortBySid(){
Student temp=null;
for(int i=0;i<dateLength-1;i++){
for(int j=0;j<dateLength-i-1;j++){
if(studentList[j].compareTo(studentList[j+1])<0){
//如果字符串比後面的小那麼就交換
System.out.println("我是排序的"+studentList[j].getSname()+"和這個交換"+studentList[j+1].getSname());
temp=studentList[j+1];
studentList[j+1]=studentList[j];
studentList[j]=temp;
}
}
}
}
//遍歷學生線性表
public void traverseList(){
for(int i=0;i<dateLength;i++){
System.out.println("姓名是:"+studentList[i].getSname()+",學號是:"+studentList[i].getSid());
}
}
//擴展數組的方法
public Student[] extendList(){
Student[] temp=new Student[studentList.length+listLength];
//然後將原來的數據複製到新的數組裏面
System.arraycopy(studentList, 0, temp, 0, studentList.length);
//然後讓原來的數組繼續指向新的數組那麼新數組的長度就變長了 實現了動態的添加長度
return temp;
}
}
總結:
1、在實現線性表的存儲結構在排序的時候有一個問題想了很久,按姓名降序排序時爲什麼張90的排在張100的前面?
關於這個問題我總結了一下:在java中String的compareTo(String compareString)方法是將原字符串和參數字符串轉換爲ASCII碼值進行比較的。而張90和張100字符串,字符串9的ASCII碼值大於1的ASCII碼值所有有張90>張100。所以纔會是張90排在張100的前面。
2、那麼如何實現字符串和數字的混合排序呢?例如張90和張100,在我寫的線性表中姓是不重要的排序取決於後面的數字,可是姓也不排除有複姓,所以說白了就是要取出姓名中的中文或者說只需要取得姓名中的數字進行排序即可。後來想到了這樣的解決辦法。主要是用正則表達式來匹配。非數字的字符串替換爲空剩下的數字字符串強制轉換爲整型即可。在java中則是這樣實現的:
Pattern pattern=Pattern.compile("[^0-9]"); //模式定義 找到字符串中不是0-9中的
Matcher matcher=pattern.matcher(this.getSname()); //在給定的姓名字符串中匹配模式中的字符串
int name=Integer.parseInt(matcher.replaceAll("") ); //替換匹配到的字符串