Java數據結構之順序表詳解
一. 線性表
1.1 定義
線性表(linear list)是n個具有相同特性的數據元素的有限序列。 線性表是一種在實際中廣泛使用的數據結構,常見的線性表:順序表、鏈表、棧、隊列、字符串… 線性表在邏輯上是線性結構,也就說是連續(xù)的一條直線。但是在物理結構上并不一定是連續(xù)的,線性表在物理上存儲時,通常以數組和鏈式結構的形式存儲。
看這個定義 我們再聯想前面的知識
是不是發(fā)現數組的使用和這個定義十分相似
沒錯 其實順序表本質上就是數組
但是它再數組上增加了一點內容
1.2 特點
它分為靜態(tài)的和動態(tài)的
這個特點是不是又發(fā)現和我們上面做的項目通訊錄十分相似
它是連續(xù)存儲的 不能跳過元素
二. 順序表
2.1 定義
順序表是用一段物理地址連續(xù)的存儲單元依次存儲數據元素的線性結構,一般情況下采用數組存儲。在數組上完成數據的增刪查改。
2.2 代碼
struct SeqList
{
int a[100]; //數組
int size; //數組中存儲了多少個數字
};我們說類似這個結構的 就是一個順序表
但是呢 為了我們以后改變數字方便 我們可以把這里的100 定義成一個宏 這樣我們以后如果想修改順序
表的大小 只要改變宏就可以了
代碼表示如下
// 靜態(tài)順序表
#define N 100
struct SeqList
{
int a[N]; //數組
int size; //數組中存儲了多少個數字
};上面就是一個標準的靜態(tài)數據表 假如說 我們想使用順序表來管理一個字符串
#define N 100
struct SeqList
{
char a[N]; //數組
int size; //數組中存儲了多少個數字
};我們可以改變int類型 變?yōu)閏har類型的數據 但是這樣每次改也太麻煩了 所以我們依舊可以再上面定義
一個宏變量
#define N 100
typedef char SLDateType
struct SeqList
{
int SLDateType[N]; //數組
int size; //數組中存儲了多少個數字
};我們說 就可以使用這樣的格式 方便以后一次性改變所有的變量類型
但是呢 這樣子我們看整個結構體還是有點麻煩 我們再將這個結構體簡化一下
typedef struct SeqList
{
int SLDateType[N]; //數組
int size; //數組中存儲了多少個數字
}SL;這樣子就能得到一個相對完美的靜態(tài)順序表啦
2.3 功能需求
在創(chuàng)建好這個靜態(tài)表之后 我們要開始大概創(chuàng)建它的一些功能啦
比如說以下的一些功能
vovoid SeqListInit(SL* ps); void SeqListPushBack(SL* ps, SLDateType x); void SeqListPopBack(SL* ps); void SeqListPushFront(SL* ps, SLDateType x); void SeqListPopFront(SL* ps);
初始化 尾插 頭插等等
2.4 靜態(tài)順序表的特點以及缺點
特點: 如果滿了就不讓插入
缺點: 不知道給多少合適
2.5 動態(tài)的順序表
typedef struct SeqList
{
SLDateType* a; //數組
int size; //數組中存儲了多少個數字
int capacity;
}SL;是不是跟我們的通訊錄特別相似
其實原理本質上都是一樣的 這里只是命名更加規(guī)范了
2.6 動態(tài)順序表接口的實現
初始化
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = ps->capacity = 0;
}尾插

我們先寫空間足夠的情況
void SeqListPushBack(SL* ps, SLDateType x)
{
ps->a[ps->size] = x;
ps->size++;
}代碼表示如上
那么我們接下來我們寫上面的兩種情況
這里我們要注意的是 一開始我們將指針置空 占用的空間為0
所以說我們一開始至少要開始4個數據的空間 這里可以使用一個三目操作符解決
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
養(yǎng)成良好的習慣 代碼加注釋
void SeqListPushBack(SL* ps, SLDateType x)
{
// 如果沒有空間或者空間不足 我們就擴容
// 擴容失敗就報錯
if ((ps->size)==(ps->capacity))
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
SLDateType* tmp =(SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
if (tmp==NULL)
{
perror("pushback realloc");
}
}
ps->a[ps->size] = x;
ps->size++;
}這里我們使用一個打印函數看看整個數據的內容
void SeqListPrint(SL* ps)
{
int i = 0;
for ( i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}打印出結果如下

在使用完成之后我們還需要一個借口函數來釋放我們的動態(tài)開辟的內存 從而避免內存泄漏的問題
void SeqListDestory(SL* ps)
{
free(ps->a);
ps->a == NULL;
ps->capacity = ps->size = 0;
}接下來我們看尾刪函數
void SeqListPopBack(SL* ps)
{
ps->size--;
}尾刪的話其實我們只要將size-- 就可以
但是這里我們要注意一點 當size為0的時候 這里就不可以再刪除了 所以我們還需要完善以下上面的代碼
void SeqListPopBack(SL* ps)
{
if (ps->size==0)
{
perror("SeqListPopBack");
}
ps->size--;
}接下來我們看前插
void SeqListPushFront(SL* ps, SLDateType x)
{
// 考慮擴容問題
if ((ps->size) == (ps->capacity))
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
ps->capacity = newcapacity;
SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
if (tmp == NULL)
{
perror("pushback realloc");
}
ps->a = tmp;
}
// 頭插
int end = ps->size - 1;
while (end>=0)
{
ps->a[end + 1] = ps->a[end];
}
ps->a[0] = x;
ps->size++;
}接下來我們來看頭刪

這就要求我們定義一個bejin 然后從前往后依次挪數據
代碼表示如下
void SeqListPopFront(SL* ps)
{
int bejin = 0;
while (bejin<ps->size-1)
{
ps->a[bejin] = ps->a[bejin + 1];
bejin++;
}
ps->size--;
}
這里我們基本實現了順序表的所有接口函數啦
三. 代碼
頭文件
#pragma once
#define N 100
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLDateType;
typedef struct SeqList
{
SLDateType* a; //數組
int size; //數組中存儲了多少個數字
int capacity;
}SL;
void SeqListInit(SL* ps);
void SeqListDestory(SL* ps);
void SeqListPushBack(SL* ps, SLDateType x);
void SeqListPopBack(SL* ps);
void SeqListPushFront(SL* ps, SLDateType x);
void SeqListPopFront(SL* ps);
void SeqListPrint(SL* ps);
// .
//...主文件
#define _CRT_SECURE_NO_WARNINGS 1
#include "seqlist.h"
void SeqListInit(SL* ps)
{
ps->a = NULL;
ps->size = ps->capacity = 0;
}
void SeqListPrint(SL* ps)
{
int i = 0;
for ( i = 0; i < ps->size; i++)
{
printf("%d ", ps->a[i]);
}
printf("\n");
}
void SeqListPushBack(SL* ps, SLDateType x)
{
// 如果沒有空間或者空間不足 我們就擴容
// 擴容失敗就報錯
if ((ps->size)==(ps->capacity))
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
ps->capacity = newcapacity;
SLDateType* tmp =(SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
if (tmp==NULL)
{
perror("pushback realloc");
}
ps->a = tmp;
}
ps->a[ps->size] = x;
ps->size++;
}
void SeqListDestory(SL* ps)
{
free(ps->a);
ps->a = NULL;
ps->capacity = ps->size = 0;
}
void SeqListPopBack(SL* ps)
{
if (ps->size==0)
{
perror("SeqListPopBack");
}
ps->size--;
}
void SeqListPushFront(SL* ps, SLDateType x)
{
// 考慮擴容問題
if ((ps->size) == (ps->capacity))
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
ps->capacity = newcapacity;
SLDateType* tmp = (SLDateType*)realloc(ps->a, newcapacity * sizeof(SLDateType));
if (tmp == NULL)
{
perror("pushback realloc");
}
ps->a = tmp;
}
// 頭插
int end = ps->size - 1;
while (end >= 0)
{
ps->a[end + 1] = ps->a[end];
end--;
}
ps->a[0] = x;
ps->size++;
}
void SeqListPopFront(SL* ps)
{
int bejin = 0;
while (bejin<ps->size-1)
{
ps->a[bejin] = ps->a[bejin + 1];
bejin++;
}
ps->size--;
}測試文件
#define _CRT_SECURE_NO_WARNINGS 1
#include "seqlist.h"
int main()
{
SL a1;
SeqListInit(&a1);
SeqListPushBack(&a1, 1);
SeqListPushBack(&a1, 2);
SeqListPushBack(&a1, 3);
SeqListPushBack(&a1, 4);
SeqListPushBack(&a1, 5);
SeqListPrint(&a1);
SeqListPopBack(&a1);
SeqListPrint(&a1);
SeqListPopFront(&a1);
SeqListPrint(&a1);
SeqListDestory(&a1);
return 0;
}到此這篇關于Java數據結構之順序表詳解的文章就介紹到這了,更多相關Java順序表內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java并發(fā)編程之synchronized底層實現原理分析
這篇文章主要介紹了Java并發(fā)編程之synchronized底層實現原理,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02
詳解SpringBoot+Mybatis實現動態(tài)數據源切換
這篇文章主要介紹了詳解SpringBoot+Mybatis實現動態(tài)數據源切換,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-05-05

