數據結構學習筆記1---線性表--數組

數據結構學習筆記1---線性表--數組

數據結構思惟導圖

mark

一些零散的概念

數據結構相關

  • 咱們把數據結構分爲邏輯結構物理結構
  • 邏輯結構:是指數據對象中數據元素之間的相互關係
  • 物理結構:是指數據的邏輯結構在計算機中的存儲形式
  • 四大邏輯結構:
    • 集合結構:集合結構中的數據元素除了同屬於一個集合外沒有其餘的相互關係。
    • 線性結構:線性結構中的數據元素之間是一對一的關係。
    • 樹形結構:樹形結構中的元素之間存在一種一對多的層次關係。
    • 圖形結構:圖形結構的元素之間是多對多的關係。
  • 數據元素的存儲形式:
    • 順序存儲:把數據元素存放在地址連續的存儲單元裏,其數據間的邏輯關係和物理關係是一致的。
    • 鏈式存儲:把數據元素存放在任意的存儲單元裏,這組存儲單元能夠是連續的,也能夠是不聯繫的。

算法相關

算法的概念和性質略過算法

  • 算法的複雜度數組

    • 時間複雜度(經常使用)
    • 空間複雜度
    例子 時間複雜度 術語
    5201314 O(1) 常數階
    3n+4 O(n) 線性階
    3n²+4n+5 O(n²) 平方階
    3log2n+4 O(logn) 對數階
    2n+3nlog2n+14 O(nlogn) nlogn階
    n3+2n2+4n+6 O(n3) 立方階
    2n O(2n) 指數階
    • 常見的時間複雜度所耗費的時間從小到大依次是:

            O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < (nn)數據結構

  • 複雜度分析法則學習

    1)單段代碼看高頻:好比循環。
    2)多段代碼取最大:好比一段代碼中有單循環和多重循環,那麼取多重循環的複雜度。
    3)嵌套代碼求乘積:好比遞歸、多重循環等
    4)多個規模求加法:好比方法有兩個參數控制兩個循環的次數,那麼這時就取兩者複雜度相加。code

  • 時間複雜度分析對象

    只關注循環執行次數最多的一段代碼
    加法法則:總複雜度等於量級最大的那段代碼的複雜度
    乘法法則:嵌套代碼的複雜度等於嵌套內外代碼複雜度的乘積blog

  • 幾個常見例子遞歸

    線性階it

int i, n = 100, sum = 0;
for(i = 0; i<n; i++) {
    sum = sum + i;
}

上面這段代碼的循環複雜度爲O(n),由於循環體中的代碼須要執行n次io

平方階

int i,j,n = 100;
for(i = 0; i < n; i++) {
    for(j = 0; j < n; j++) {
        printf("aaaaaaaaaaaa\n");
    }
}

上面這段代碼的時間複雜度爲O(n²)

int i,j,n = 100;
for(i = 0; i < n; i++) {
    for(j = i; j < n; j++) {
        pringtf("aaaaaaaaaaaaaa\n");
    }
}

分析,因爲當i=0時,內循環執行了n次,當i=1時,內循環則執行n-1次。。。。。。當i=n-1時,內循環執行1次,因此總的執行次數應該是n+(n-1)+(n-2)+...+1=n(n+1)/2用上面的簡化方法來簡化½n²+½n,這個式子中沒有常數項不用考慮第一條,根據第二條只保留最高項,去掉½n這一項,根據第三條去掉與最高項相乘的常數½,最終獲得O(n²)

對數階

int i = 1, n = 100;
while(i < n) {
    i = i*2;
}

因爲每次i2以後就距離n更近一步,假設有x個2相乘後大於或等於n,則會退出循環。因而由2^x=n

獲得x=log2n,因此這個循環的時間複雜度爲O(logn)。

ADT(抽象數據結構)

抽象數據類型的定義格式以下:

ADT抽象數據類型名{

    數據對象:(數據對象的定義〉
    數據關係:(數據關係的定義〉
    基本操做:(基本操做的定義〉
    
}ADT抽象數據類型名

基本操做的定義格式爲:

​ 基本操做名(參數表)

​ 初始條件:(初始條件描述〉

​ 操做結果:(操做結果描述〉

基本操做有兩種參數: 賦值參數只爲操做提供輸入值;引用參數以"&"打頭,除可提供輸

入值外,還將返回操做結果。

線性表之數組

mark

什麼是線性表

對非空的線性表或線性結構, 其特色是:

  1. 存在惟一的一個被稱做 「第一個" 的數據元素;
  2. 存在惟一的一個被稱做 「最後一個" 的數據元素;
  3. 除第一個以外, 結構中的每一個數據元素均只有一個前驅;
  4. 除最後一個以外,結構中的每一個數據元素均只有一個後繼。

線性表的抽象數據類型

ADT List{ 
    數據對象: D={ai|ai E ElemSet, i=l, 2, …n, n>=0} 
    數據關係: R=(<ai-1,ai> ai-1,aiE D, i=2, …, n} 
    基本操做:
    InitList (&L) 
        操做結果:構造一個空的線性表L。

    DestroyList(&L) 
        初始條件:線性表L已存在。
        操做結果:銷燬線性表L。
    
    ClearList (&L) 
        初始條件:線性表L已存在。
        操做結果:將L重置爲空表。
        
    ListEmpty(L)
        初始條件:線性表L已存在。
        操做結果:若L爲空表, 則返回true, 不然返回false。
        
    ListLength(L) 
        初始條件:線性表L已存在。
        操做結果:返回L中數據元素個數。
        
    GetElem(L,i,&e) 
        初始條件:線性表L巳存在
        操做結果:用e返回L中第i個數據元素的值。
        
    LocateElem(L,e) 
        初始條件:線性表L已存在。
        操做結果:返回L中第1個 值與e相同的元素在 L中的位置 。若這樣的數據元素不存在 , 則返回值爲0。
        
    PriorElem(r,,cur_e,&pre_e) 
        初始條件:線性表L已存在。
        操做結果:若cur_e是L的數據元素,且不是第一個,則用pre_e返回其前驅,不然操做失敗,pre_e無定義。
    NextElem(L,cur_e,&next_e) 
        初始條件:線性表L已存在。
        操做結果:若cur_e是L的數據元素,且不是最後一個,則用next_e返回其後繼,不然操做失敗,next_e無定義。
        
    Listinsert(&L,i,e) 
        初始條件:線性表L已存在,且1:,s;i:os;ListLength (L) +l。
        操做結果:在 L中第1個位置以前插入新的數據元素 e, L的長度加1。
        
    ListDelete(&L,i) 
        初始條件:線性表L已存在且非空 ,且l:os;i:os;ListLength(L)。
        操做結果:刪除L的第1個數據元素,L的長度減1。
        
    TraverseList(L) 
        初始條件:線性表L已存在。
        操做結果:對線性表L進行遍歷,在遍歷過程當中對 L的每一個結點訪問一次。
        
) ADT List

順序表

//----- 順序表的存儲結構----- //

#define MAXSIZE 100 //順序表可能達到的最大長度
typedef struct {
     ElemType  *elem           //聲明瞭一個名爲elem的長度不肯定的數組,也叫「動態數組」,也能夠聲明爲                                //data[MAXSIZE];   
	int  Length;      		 //當前長度    
}SqList;                      //順序表的結構類型爲SqList

幾種典型算法

初始化

算法步驟:

  1. 爲順序表L動態分配一個預約義大小的數組空間,使elem指向這段空間的基地址。
  2. 將表的當前長度設爲0。

算法描述:

Status InitList(SqList &L){
    //構造一個空的順序表
    L.elem=(ElemType *)malloc(MAXSIZE*sizeof(ElemType));  //爲順序表分配空間,也能夠用new
    if (!L.elem) exit(OVERFLOW);                          //分配空間失敗,退出
    L.Length=0;                                           //初始化長度爲0
    return OK;
}

取值

算法步驟 :

  1. 判斷指定的位置序號 i 值是否合理 (I<=i<=L.length), 若不合理,則返回ERROR。
  2. 若 i 值合理,則將第 i 個數據元素 L.elem[i-1]賦給參數 e, 經過 e返回第 1 個數據元素的傳值。

算法描述:

Status GetElem(SqList L,int i,ElemType &e){
    if (i<1||i>L.Length) return ERROR;   //判斷數據不合理
     e=L.elem[i-1];
    return OK;  
}

查找:

算法步驟 :

  1. 從第一個元素起,依次和 e相比較,若找到與 e相等的元素 L.elem[i], 則查找成功,返回該元素的位置 i+l。

  2. 若查遍整個順序表都沒有找到,則查找失敗, 返回0。

算法描述:

int  LocateELem(SqList L,ElemType e){
    //在順序表1中查找值爲e的數據元素, 返回其序號
    for (i=0;i<L.Length;i++){
        if (L.elem[i]==e)  return i+1;       //查找成功
    }
    return 0;                                //查找失敗
}

插入

算法步驟 :

  1. 先判斷插入位置是否合理(1<=i<=n+1)
  2. 判斷順序表的存儲空間是否已滿,;
  3. 若滿見膚返回 ERROR。
  4. 將第n個至第i個位置的元素依次向後移動一個位置,空出第i個位置(i =n+l 時無需移動)。
  5. 將要插入的新元素e放入第i個位置。
  6. 表長加1。

算法描述:

Status ListInit(SqList &L,int i,ElemType e){
    if (i<1||i>L.Length+1)  return ERROR;     //插入位置不合理
    if (L.Length==MaixSize)  return ERROR;   //順序表已滿
    for (j=L.Length-1;j>=i-1;j--){
        L.elem[j+1]= L.elem[j];               //從後向前依次後移
	}
    L.elem[i-1]=e                             //插入新元素
    L.Length++;								//長度加1
    return OK;   
}

刪除

算法步驟 :

  1. 先檢查刪除的位置是否合理(1<=i<=n)
  2. 將第i+1個至第n個的元素依次向前移動一個位置 (i = n時無需移動)。
  3. 表長減 1。

算法描述:

Status ListDelete(SqList &L,int i){
    if (i<1||i>L.Length)    return ERROR;         //插入位置不合理
    for (j=i;j<=L.Length-1;j++){
        L.elem[j-1]=L.elme[j];
    }
    --L.Length;
    return OK;  
}

c語言實現

#include <stdio.h>
#include <stdlib.h>
#define Size 5
typedef struct Table{
    int * head;
    int length;
    int size;
}table;

//初始化順序表
table initTable(){
    table t;
    t.head=(int*)malloc(Size*sizeof(int));
    if (!t.head)
    {
        printf("初始化失敗");
        exit(0);
    }
    t.length=0;
    t.size=Size;
    return t;
}

//添加元素
table addTable(table t,int elem,int add)
{
    if (add>t.length+1||add<1) {
        printf("插入位置有問題");
        return t;
    }
    if (t.length>=t.size) {
        t.head=(int *)realloc(t.head, (t.size+1)*sizeof(int));
        if (!t.head) {
            printf("存儲分配失敗");
        }
        t.size+=1;
    }
    for (int i=t.length-1; i>=add-1; i--) {
        t.head[i+1]=t.head[i];
    }
    t.head[add-1]=elem;
    t.length++;
    return t;
}

//刪除元素
table delTable(table t,int add){
    if (add>t.length || add<1) {
        printf("被刪除元素的位置有誤");
        exit(0);
    }
    for (int i=add; i<t.length; i++) {
        t.head[i-1]=t.head[i];
    }
    t.length--;
    return t;
}

//查找元素
int selectTable(table t,int elem){
    for (int i=0; i<t.length; i++) {
        if (t.head[i]==elem) {
            return i+1;
        }
    }
    return -1;
}

//修改元素
table amendTable(table t,int elem,int newElem){
    int add=selectTable(t, elem);
    t.head[add-1]=newElem;
    return t;
}

//遍歷輸出
void displayTable(table t){
    for (int i=0;i<t.length;i++) {
        printf("%d ",t.head[i]);
    }
    printf("\n");
}


int main(){
    table t1=initTable();
    for (int i=1; i<=Size; i++) {
        t1.head[i-1]=i;
        t1.length++;
    }
    printf("原順序表:\n");
    displayTable(t1);
  
    printf("刪除元素1:\n");
    t1=delTable(t1, 1);
    displayTable(t1);
  
    printf("在第2的位置插入元素5:\n");
    t1=addTable(t1, 5, 2);
    displayTable(t1);
  
    printf("查找元素3的位置:\n");
    int add=selectTable(t1, 3);
    printf("%d\n",add);
  
    printf("將元素3改成6:\n");
    t1=amendTable(t1, 3, 6);
    displayTable(t1);
    return 0;
}

輸出:

原順序表:
1 2 3 4 5
刪除元素1:
2 3 4 5
在第2的位置插入元素5:
2 5 3 4 5
查找元素3的位置:
3
將元素3改成6:
2 5 6 4 5
相關文章
相關標籤/搜索