1. 程式人生 > >【資料結構】實現順序表以及簡單的時間複雜度分析

【資料結構】實現順序表以及簡單的時間複雜度分析

最近在學資料結構,接下來一段時間我將用java來實現所學的各種資料結構,以加深自己的印象。

線性表包括順序表和連結串列,其實順序表就是動態陣列,下面我將二次封裝實現屬於自己的動態陣列。

-----------------------------------------------------------------------------------------------------------------------------------------------------

陣列類:Array

陣列名:data

陣列容量:capacity

已存放元素個數:size

方法:

①獲取陣列中元素個數(getSize

②獲取陣列容量(getCapacity

③返回陣列是否為空(isEmpty

④向陣列末尾新增元素(addLast

⑤向指定索引位置新增元素(add

⑥向所有元素前新增一個新元素(addFirst

⑦得到指定索引位置的元素(get

⑧修改指定索引位置的元素(set

⑨查詢陣列中是否有指定元素(contains

⑩查詢陣列中指定元素的索引(find

⑪刪除指定索引位置的元素(remove

⑫刪除陣列中第一個元素(removeFirst

⑬刪除陣列最後一個元素(removeLast

⑭查詢指定元素並刪除(removeElement

⑮實現擴容和縮容(resize

當然感興趣的可以繼續新增自己想要的功能,比如刪除全部元素等等。

-----------------------------------------------------------------------------------------------------------------------------------------------

public class Array<E> {
	private E[] data;
	private int size;// 陣列中元素個數

	// 建構函式,傳入陣列容量capacity構造Array
	public Array(int capacity) {
		data = (E[]) new Object[capacity];
		size = 0;
	}

	// 無引數建構函式,預設陣列容量為10
	public Array() {
		this(10);
	}

	// 獲取陣列容量
	public int getCapacity() {
		return data.length;
	}

	// 獲取陣列中元素個數
	public int getSize() {
		return size;
	}

	// 返回陣列是否為空
	public boolean isEmpty() {
		return size == 0;
	}

	// 向陣列所有元素前新增元素
	public void addFirst(E e) {
		add(0, e);
	}

	// 向陣列末尾新增元素
	public void addLast(E e) {
		add(size, e);
	}

	// 向陣列index位置插入元素e
	public void add(int index, E e) {
		if (index < 0 || index > size)
			throw new IllegalArgumentException("操作失敗,需要滿足 index<0 || index>size");
		if (size == data.length)
			resize(data.length << 1);// 實現兩倍擴容
		// 使元素往後挪一個位置
		for (int i = size - 1; i >= index; i--)
			data[i + 1] = data[i];
		data[index] = e;
		size++;
	}

	// 得到指定索引上的陣列元素
	public E query(int index) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("操作失敗,需要滿足 index < 0 || index >= size");
		return data[index];
	}

	// 獲得第一個元素
	public E getFirst() {
		return query(0);
	}

	// 獲得最後一個元素
	public E getLast() {
		return query(size - 1);
	}

	// 將指定索引上的元素修改成e
	public void modify(int index, E e) {
		data[index] = e;
	}

	// 查詢陣列中是否有元素e
	public boolean contains(int e) {
		for (int i = 0; i < size; i++)
			if (data[i].equals(e))
				return true;
		return false;
	}

	// 查詢陣列中指定元素的一個索引
	public int find(E e) {
		for (int i = 0; i < size; i++)
			if (data[i].equals(e))
				return i;
		return -1;
	}

	// 刪除指定索引上的元素,返回刪除元素
	public E remove(int index) {
		if (index < 0 || index >= size)
			throw new IllegalArgumentException("操作失敗,需要滿足 index < 0 || index >= size");
		E temp = data[index];
		for (int i = index + 1; i < size; i++)
			data[i - 1] = data[i];
		size--;
		data[size] = null;// loitering objects
		if (size == data.length >> 2 && data.length >> 1 != 0)// 防止複雜度震盪,當元素個數為容量的1/4時才執行縮容
			resize(data.length >> 1);// 實現對半縮容
		return temp;
	}

	// 刪除陣列第一個元素,返回刪除元素
	public E removeFirst() {
		return remove(0);
	}

	// 刪除陣列最後一個元素,返回刪除元素
	public E removeLast() {
		return remove(size - 1);
	}

	// 查詢陣列一個元素e並刪除
	public void removeElement(E e) {
		int index = find(e);
		if (index != -1)
			remove(index);
	}

	@Override
	public String toString() {
		StringBuilder res = new StringBuilder();
		res.append(String.format("元素個數:%d,容量大小:%d\n", size, data.length));
		res.append('[');
		for (int i = 0; i < size; i++) {
			res.append(data[i]);
			if (i != size - 1)
				res.append(",");
		}
		res.append(']');
		return res.toString();
	}

	// 定義陣列擴容方法
	private void resize(int newCapacity) {
		E[] newData = (E[]) new Object[newCapacity];
		for (int i = 0; i < size; i++)
			newData[i] = data[i];
		data = newData;// 將新陣列的地址指向舊陣列
	}
}

-----------------------------------------------------------------------------------------------------------------------------------------------

簡單時間複雜度分析:

①新增操作(刪除操作等同)

addLast(e)           可能觸發resize擴容操作,最壞時間複雜的為O(n)

addFirst(e)           O(n)

add(index,e)      O(n/2)=O(n)

②修改操作

set(index,e)       O(1)

③查詢操作

get(index)             O(1)

contains(e)           O(n)

find(e)                   O(n)

總結:查詢快速,新增刪除賊慢

-----------------------------------------------------------------------------------------------------------------------------------------------

均攤時間複雜度分析:

我們知道在呼叫addLast方法時,有可能會觸發resize擴容,因此最壞情況的時間複雜度是O(n),但是這樣其實是不合理的,因為每次addLast操作不一定都觸發resize

假設capacity=n,每次都使用addLast作為新增操作,當n+1次addLast操作會觸發resize擴容,將前面n個元素複製到新陣列中,因此總共執行了2n+1次操作,平均每次addLast約等於進行了兩次基本操作;

這樣均攤計算,addLast操作的時間複雜度是O(1),在這個例子裡均攤計算比計算最壞情況更有意義;

同理,removeLast操作的均攤複雜度也是O(1)。

-----------------------------------------------------------------------------------------------------------------------------------------------

複雜度震盪:

當陣列已滿時執行addLast時擴容,又馬上執行removeLast導致縮容,會造成複雜度震盪,這樣來回操作,每一個操作的時間複雜度為O(n)。

解決方法:

只需當size=capacity/4時,才將capacity減半實現縮容。

相關推薦

資料結構實現順序以及簡單時間複雜分析

最近在學資料結構,接下來一段時間我將用java來實現所學的各種資料結構,以加深自己的印象。 線性表包括順序表和連結串列,其實順序表就是動態陣列,下面我將二次封裝實現屬於自己的動態陣列。 -------------------------------------------

資料結構靜態順序各種功能實現(C語言)

順序表的儲存方式 定義一個順序表 #define MAX_SIZE (100) typedef int DataType; typedef struct SeqList { DataType data[MAX_SIZE]; int siz

C#資料結構001-線性順序

C#資料結構:順序表結構 1、自定義順序表結構 using System.Collections; using System.Collections.Generic; /// <summary> ///線性表介面 /// </summary> /// <type

資料結構無頭單鏈各個介面的實現

以下是無頭單鏈表的增刪查改等介面的實現 SList.h #pragma once #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <malloc.h> t

C#資料結構002-線性:單鏈

C#資料結構:單鏈表 1、自定義單鏈表結構: 單鏈節點類 using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 單鏈表節點 ///

資料結構實現一個棧要求實現Push(出棧)Pop(入棧)Min(返回最小值)的時間 複雜為O(1)

文章目錄 思路 MinStack.h MinStack.c Test.c 棧的基本實現: https://blog.csdn.net/weixin_41892460/article/details/8297385

資料結構雜湊/散列表

本篇博文,旨在介紹雜湊表的基本概念及其用法;介紹了減少雜湊衝突的方法;並用程式碼實現了雜湊表的線性探測和雜湊桶 雜湊表的基本概念 雜湊表是一種儲存結構,它通過key值可以直接訪問該key值在記憶體中

資料結構實現一個棧,要求實現Push(出棧)、Pop(入棧)、Min(返回最小值的操作)的時間複雜為O(1)

實現一個棧,要求實現Push(出棧)、Pop(入棧)、Min(返回最小值的操作)的時間複雜度為O(1) 在棧中操作的話,push和pop的時間複雜度就是O(1),所以我們只用實現Min(返回最小值的操作)的時間複雜度為O(1), 思想就是用兩個棧,一個就是普通的存取資料的

資料結構雜湊及雜湊桶的基本操作

  順序搜尋和二叉搜尋樹中,元素儲存位置和元素各關鍵碼之間沒有對應的關係,這就導致在查詢一個元素時,必須經過關鍵碼的多次比較。那麼是否有這樣一種資料結構,可以不經過任何比較,直接找到想要搜尋的元素呢?答案是肯定的,那就是通過某種函式(hashFunc)使得元素的儲存位置與它的

資料結構字串順序儲存結構

#include "string.h" #include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h" #define OK 1 #

資料結構演算法實現-順序基本操作

資料結構演算法實現 實現了高一凡的<<資料結構>>,書中的程式碼是基於VC6++ c++語言實現的,網上也可以找到TC版的c語言實現的原始碼,TC版的原始碼平臺是 Turbo C 2.0 ,編譯軟體相對較早,因此將採用CodeBlock

資料結構與演算法之美專欄學習筆記-複雜分析

複雜度分析 什麼是複雜度分析 資料結構和演算法解決是“如何讓計算機更快時間、更省空間的解決問題”。 因此需從執行時間和佔用空間兩個維度來評估資料結構和演算法的效能。 分別用時間複雜度和空間複雜度兩個概念來描述效能問題,二者統稱為複雜度。 複雜度描述的是演算法執行時間(或佔用空間)與資料規模的增長關係

資料結構與演算法之美 課程筆記二 複雜分析(上)

資料結構和演算法本身解決的是“快”和“省”的問題,即如何讓程式碼執行得更快,如何讓程式碼更省空間。所以,執行效率是演算法一個非常重要的考量指標。衡量演算法的執行效率最常用的就是時間和空間複雜度分析。 一、為什麼需要複雜度分析? 把程式碼跑一遍,通過統計、監控來得到演算法執行的時間和佔用的記憶

資料結構與演算法 1 」| 循序漸進理解時間複雜和空間複雜

寫在之前 我們都知道,對於同一個問題來說,可以有多種解決問題的演算法。儘管演算法不是唯一的,但是對於問題本身來說相對好的演算法還是存在的,這裡可能有人會問區分好壞的標準是什麼?這個要從「時效」和「儲存」兩方面來看。 人總是貪婪的,在做一件事的時候,我們總是期望著可以付出最少的時間、精

學習筆記與調和級數相關的時間複雜

宣告:博主寫這個部落格的理由只是為了緩解心情,大部分的東西都是我手推的,沒有驗證過,如果有問題敬請指出。 Noip2018day1完掛,非常難受,過來寫個部落格頹一下,緩解心情 1. 調和級數 調和級數

20150908資料結構(C語言版)演算法時間複雜問題

1, 演算法複雜度是在《資料結構》這門課程的第一章裡出現的,因為它稍微涉及到一些數學問題,所以很多同學感覺很難,加上這個概念也不是那麼具體,更讓許多同學複習起來無從下手,下面我們就這個問題給各位考生進行分析。 首先了解一下幾個概念。一個是時間複雜度,一個是漸

資料結構:圖之DFS與BFS的複雜分析

BFS的複雜度分析。        BFS是一種借用佇列來儲存的過程,分層查詢,優先考慮距離出發點近的點。無論是在鄰接表還是鄰接矩陣中儲存,都需要藉助一個輔助佇列,v個頂點均需入隊,最壞的情況下,空間複雜度為O(v)。     鄰接表形式儲存時,每個頂點均需搜尋一次,時間

資料結構5.1 順序的查詢以及二分查詢的實現

類的結構如下: class StaticSearchTable { private: int *data; int data_number; bool search_seq(int loc,int key); void select_sort(); bool f

資料結構陣列實現的線性(線性順序儲存結構)

資料結構 陣列實現線性表 通過陣列實現了一個簡單的線性表 功能: 在陣列尾部新增元素 在陣列指定位置新增元素 根據下標獲取元素 根據下標刪除元素 根據元素刪除元素 獲取當前陣列長度 判斷當前陣列是否為空 列印陣列元素 public

資料結構順序實現十進位制轉換任意進位制

/* & File : 進位制準換 * Author : Laugh * Copyright: Laugh * 主題 :對於輸入的任意一個非負十進位制小數,列印輸出與其等值的任意進位制小數 * Date : 2018/10/14 */