1. 程式人生 > >資料結構學習筆記(1.大O表示法和順序表)

資料結構學習筆記(1.大O表示法和順序表)

  最近在看國嵌唐老師的資料結構視訊,覺得還不錯,所以就把筆記記錄下來

本節知識點:

1.資料之間的邏輯結構:   集合結構:資料元素之間沒有特別的關係,僅同屬相同集合   線性結構:資料元素之間是一對一的關係   樹形結構:資料元素之間存在一對多的層次關係   圖形結構:資料元素之間是多對多的關係2.資料之間的物理結構    順序儲存結構:將資料儲存在地址連續的儲存單元裡    鏈式儲存結構:將資料儲存在任意的儲存單元裡,通過儲存地址的方式找到相關的資料元素3.資料結構是相互之間存在一種或多種特定關係的資料元素的集合4.程式 = 資料結構 + 演算法5.大O表示法:演算法效率嚴重依賴於運算元量,首先關注運算元的最高次項
,運算元的估計可以作為時間和空間複雜度的估算,在沒有特殊說明的時候,我們應該分析複雜度的最壞情況6.常見的複雜度型別:大小關係:7.線性表是零個或多個數據元素的集合,之間的元素是有順序的,個數是有限的,資料型別必須相同。線性表包含兩種儲存方式,一種是順序表,另一種連結串列。8.對於線性表的使用是這樣的:應該是在設計演算法的時候,考慮演算法中使用的資料,這些資料之間是什麼關係的,如果是符合線性表特質的,就選擇線性表作為資料結構。9.順序表與陣列的關係:其實順序表就是在陣列的基礎上構建的,本質跟陣列是一樣的,只是在陣列的基礎上增加了length長度,capacity容量等特性,然後補充了一些列,增、刪、改、查的功能。
10. 我覺得連結串列比順序表最大的優勢,就在於連結串列的刪除和插入要比順序表簡單的多,而且當線性表長度很大的時候很難開闢出整段的連續空間!!!最重要的是順序表在建立的時候長度就固定了,再也改變不了了,而連結串列則可以根據情況動態增加,這一點是順序表無論怎麼樣都不可能實現的!!!順序表的優點是:無需為線性表中的邏輯增加額外的空間,可以快速的通過下標的方式找到表中的合法位置。11.線性表的常用操作:建立線性表、銷燬線性表、清空線性表、將元素插入線性表、將元素從線性表中刪除、獲取線性表中某個位置的元素、獲取線性表的長度

本節程式碼:

1.本節的程式碼是一個可以適合各種型別的順序表,之所以能夠適合各種型別,是因為它在順序表中儲存的是元素的地址(其實就是一個指標陣列)。2.程式碼中的描述順序表的結構體中的元素介紹:length是順序表中有元素的個數、capacity是順序表的容量、node是順序表的頭地址(也是這個指標陣列的頭地址)、還有一個就是pos,pos是在刪除和插入的時候使用的一個引數,它代表的是插入到順序表位置的下標(陣列的下標 是從0開始的 這個很要注意)。順序表中有length個元素 下標是從0到length-1的。要注意的是 操作順序表不同功能函式的pos的允許範圍是不一樣的。
3.本節程式碼對於函式引數的合法性判斷是極其重視的,這個規範是值得學習的。4.本節程式碼中對於順序表的操作函式,凡是外界輸入的,和輸出到外界的,都是void *型別的,這樣就保證了只有在這些操作函式中才能去改變   描述順序表的結構體裡面的值,在其他檔案的函式中接受到的都是void *型別,無法直接給這個結構體中的值進行改變,這樣的封裝,保證了程式碼的安全性。5.對於本節程式碼最值得思考的地方,常見的順序表是typedef一個A型別,然後在順序表中定義一個這個A型別的陣列和length順序表元素個數,這個順序表中是好多個A型別的順序集合,佔用空間的大小是sizeof(A)*capacity。而本節的順序表中是好多個unsigned int *地址型別的順序集合,表中只有地址,第一節省了順序表的空間,第二這樣可以變相的儲存不同型別的資料,第三它實現了 順序表(即資料結構) 和 我們打算利用的資料(即元素)的分離。例如:linux核心連結串列(一個雙向迴圈連結串列)就是一套單獨的連結串列體制,這個連結串列用在很多機制上面,它就是變相的儲存了好多型別的資料,並且實現了連結串列和資料的分離。所以在main.c中  資料要想儲存在這個順序表中  就應該先給這些資料開闢記憶體    因為順序表中沒有他們呆的地方   順序表中只能儲存他們的地址。如圖:程式碼如下:Seqlist.c:
/************************************************************************************ 
檔名:Seqlist.c
標頭檔案:Seqlist.h 
時間: 2013/08/05 
作者: Hao 
功能:可以複用 帶有增 刪 改 查 功能的順序表
難點:1.順序表中存放的都是 各種資料的地址
      2.void *是用來隔離封裝用的 保證順序表結構體只能被特定的函式改變 
************************************************************************************/
#include <stdio.h>
#include <malloc.h>
#include "Seqlist.h"

typedef unsigned int TSeqListNode;//這個順序表中存放的是 各種資料的地址 所以用unsigned int 
typedef struct str_SeqList
{
	int length;//順序已用的長度 
	int capacity;//順序表的總容量 
	TSeqListNode* node;//這個指標是用來在順序表中游走讀取資料用的 
}TSeqList;  //定義描述順序表的結構體 

/************************************************************************************ 
函式名:   Creat_SeqList
函式功能: 建立一個容量為capacity的順序表 
引數:     int capacity 建立順序表中成員的個數 即順序表容量
返回值:   void* ret 如果返回NULL 說明建立順序表失敗
                     如果返回ret 說明建立順序表成功  且ret為描述順序表的結構體 
************************************************************************************/
SeqList* Creat_SeqList(int capacity)
{
	TSeqList* ret = NULL;
	/*進入函式 第一點是先判斷傳人蔘數的合法性*/
	if(capacity >= 0)
	{
		/*給順序表開闢空間*/
		ret=(TSeqList* )malloc(sizeof(TSeqList)+sizeof(TSeqListNode)*capacity);
		if(NULL!=ret)//空間開闢成功   給描述順序表的結構體 賦值 
		{
			ret->capacity=capacity;
			ret->length=0;
			ret->node=(TSeqListNode* )(ret+1);//把真正順序表的地址賦給 node 
		}
	}
	else
	{
		ret = NULL;
	} 
	return (SeqList*)(ret);
} 

/************************************************************************************ 
函式名:   Destroy_SeqList
函式功能: 銷燬順序表   free開闢的記憶體 
引數:     void* list 描述順序表結構體指標
返回值:   void 
************************************************************************************/
void  Destroy_SeqList(SeqList* list)
{
	free(list);
}

/************************************************************************************ 
函式名:  Get_Seqlist_Length
函式功能:獲得順序表 現在的大小
函式引數:void* list 描述順序表結構體指標
函式返回值:int ret  成功返回length
                     失敗返回-1 
************************************************************************************/
int Get_Seqlist_Length(SeqList* list)
{
	int ret;
	TSeqList *Tlist=(TSeqList* )list;
	/*函式引數合法性檢測*/
	if(NULL != Tlist)
	{
		ret=Tlist->length;
	} 
	else
		ret=-1;
	return ret;
}

/************************************************************************************
函式名:  Get_Seqlist_Capacity
函式功能:獲得順序表 的容量 
函式引數:void* list 描述順序表結構體指標
函式返回值:int ret  成功返回capacity 
                     失敗返回-1 
************************************************************************************/
int Get_Seqlist_Capacity(SeqList* list)
{
	int ret;
	TSeqList *Tlist=(TSeqList* )list;
	/*函式引數合法性檢測*/
	if(NULL != Tlist)
	{
		ret = Tlist->capacity;
	} 
	else
		ret=-1;
	return ret;
}

/************************************************************************************ 
函式名:  Clean_Seqlist_Length
函式功能:清空順序表  其實就是給length=0; 
函式引數:void* list 描述順序表結構體指標
函式返回值:int ret  成功返回0
                     失敗返回-1 
************************************************************************************/
int Clean_Seqlist_Length(SeqList* list)
{
	int ret;
	TSeqList *Tlist=(TSeqList* )list;
	/*函式引數合法性檢測*/
	if(NULL != Tlist)
	{
		Tlist->length=0;
		ret=0;
	} 
	else
		ret=-1;
	return ret;
}

/************************************************************************************
函式名:  Seqlist_Add
函式功能:順序表中有length個數據  在下標為pos的位置上 插入資料node  所以pos是從0開始的 length是從1開始的 
引數:      SeqList* list描述順序表的結構體地址   SeqListNode* node插入順序表的資料的地址  
		   int pos插入順序表的位置   pos的範圍是從0(此時在順序表頭部插入)開始  到length(此時就是在順序尾部插入)
		    總共是length+1個位置 
返回值 :  返回1 說明插入資料成功  返回0 說明插入資料失敗
************************************************************************************/
int Seqlist_Add(SeqList* list, SeqListNode* node ,int pos)
{
	/*引數合法性檢測*/
	TSeqList *Tlist=(TSeqList* )list;
	int ret = (NULL != list);
	int i;
	ret=ret && (pos >= 0);
	ret=ret && (Tlist->length+1 <= Tlist->capacity);  //判斷再插入一個數據的時候  length有沒有超過 capacity 
	if(1 == ret)
	{
		if(pos >= Tlist->length)//如果插入的位置pos比 length大的話 預設把length+1賦值給pos 
		{
			pos = Tlist->length;
		}
		for(i=Tlist->length;i>pos;i--)
		{
			Tlist->node[i]=Tlist->node[i-1];
		} 
		Tlist->node[i]=(TSeqListNode)node; //把要插入的地址強制型別轉換成 unsigned int* 
		Tlist->length++;
	} 
	return ret;//返回1 說明插入資料成功  返回0 說明插入資料失敗 
}	

 
/************************************************************************************
函式名:   Get_Node
函式功能:找到順序表中下標為pos的值  
引數:    pos插入順序表的下標   pos的範圍是從0到length-1   
          SeqList* list描述順序表的結構體地址
返回值:  void* ret 找到pos為下標的那個值
        如果成功返回pos為下標的那個值   如果失敗  返回NULL
************************************************************************************/

SeqListNode* Get_Node(SeqList* list, int pos)
{
	TSeqList* Tlist=(TSeqList* )list;
	SeqListNode* ret=NULL;
	if( (NULL!=Tlist) && (pos>=0) && (pos<Tlist->length) )
	{
		ret=(SeqListNode* )Tlist->node[pos]; //強制型別轉換成void*  
	}
	return ret;
} 

/************************************************************************************
函式名:   Del_Node
函式功能:找到順序表中下標為pos的值  並且刪除它 
引數:    刪除pos為下標的值   pos的範圍是從0到length-1   
          SeqList* list描述順序表的結構體地址
返回值:  void* ret 
          如果成功返回pos為下標的那個值   如果失敗  返回NULL 
************************************************************************************/
SeqListNode* Del_Node(SeqList* list, int pos)
{
	TSeqList* Tlist=(TSeqList* )list;
	SeqListNode* ret=NULL;
	int i;
	if( (NULL!=Tlist) && (pos>=0) && (pos<Tlist->length) )
	{
		ret=(SeqListNode* )Tlist->node[pos];
		for(i=pos+1; i<Tlist->length; i++)
		{
			Tlist->node[i-1]=Tlist->node[i];
		}
		Tlist->length--;
	}
	return ret;
}



Seqlist.h:
#ifndef __Seqlist__
#define __Seqlist__

typedef void SeqList;  //是用來封裝 使順序表結構體 不被外界改變 只可被Seqlist.c檔案中的函式改變
                       //因為 這些函式 對外的介面 都是void*  
typedef void SeqListNode;//SeqList 是用來表示 順序表的    SeqListNode是用來表示順序表 中變數的 

SeqList* Creat_SeqList(int capacity);
void  Destroy_SeqList(SeqList* list);
int Get_Seqlist_Length(SeqList* list);
int Get_Seqlist_Capacity(SeqList* list);
int Clean_Seqlist_Length(SeqList* list);
int Seqlist_Add(SeqList* list, SeqListNode* node ,int pos);
SeqListNode* Get_Node(SeqList* list, int pos);
SeqListNode* Del_Node(SeqList* list, int pos); 

#endif

main.c:
#include <stdio.h>
#include <stdlib.h>
#include "Seqlist.h"
int main(int argc, char *argv[])
{
	SeqList* My_SeqList = NULL;
	int a = 10;
	int b = 5;
	int c = 3;
	int d = 6;
	int e = 1;
	int *p = NULL;
	int i = 0;
	My_SeqList = Creat_SeqList(5);
	if( NULL != My_SeqList )
	{
			Seqlist_Add(My_SeqList, &a ,0);
			Seqlist_Add(My_SeqList, &b ,0);
			Seqlist_Add(My_SeqList, &c ,0);
			Seqlist_Add(My_SeqList, &d ,0);
			Seqlist_Add(My_SeqList, &e ,0);
			
			for(i=0; i<Get_Seqlist_Length(My_SeqList); i++)
			{
				p=Get_Node(My_SeqList, i);
				printf("%d\n",*p);
			}
			
			Del_Node(My_SeqList, 3);
			for(i=0; i<Get_Seqlist_Length(My_SeqList); i++)
			{
				p=Get_Node(My_SeqList, i);
				printf("%d\n",*p);
			}
			
	} 
	Clean_Seqlist_Length(My_SeqList);
	Destroy_SeqList(My_SeqList);
	return 0;
}


仔細觀察下面錯誤程式碼,test_main.c:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "Seqlist.h"

typedef struct student
{
	int student_num;
	char name[30];
	char sex[20];
	int age;
}str;
int main()
{
	str* str1;
	SeqList* slist=NULL;
	int i=0;
	int age=0;
	slist=Creat_SeqList(50);
	if(NULL == slist)
	{
		printf("malloc error!!!\n");
		return -1;
	}
	for(i=0; i<3; i++)
	{
		put_student(slist, str1);
	}
	
	printf("輸入你要刪除的年齡:\n");
	scanf("%d",&age);
	printf("\n");
	find_student(slist, str1, age);
	get_student(slist, str1);
	
	destroy_student(slist, str1);
	Clean_Seqlist_Length(slist);
	Destroy_SeqList(slist);
	return 0;
}

int put_student(SeqList* slist, str* str1)
{ 
	int num;
	int ret=(NULL != str1);
	if(1 == ret)
	{
		ret=ret && Seqlist_Add(slist, (str* )malloc(sizeof(str)*1) ,50);
		num = Get_Seqlist_Length(slist);
		str1 = (str* )Get_Node(slist, num-1);
		printf("請輸入學生學號:\n"); 
		scanf("%d",&str1->student_num);
		printf("請輸入學生姓名:\n");
		scanf("%s",str1->name);
		printf("請輸入學生性別:\n");
		scanf("%s",str1->sex);
		printf("請輸入學生年齡:\n");
		scanf("%d",&str1->age);
		printf("\n"); 
	}		
	else
	{
		ret = 0;
	}
	return ret;
}

int get_student(SeqList* slist, str* str1)
{
	int ret=(NULL != str1);
	int i=0;
	if(1 == ret)
	{
		for(i=0; i<Get_Seqlist_Length(slist); i++)
		{
			str1 = (str*)Get_Node(slist, i);
			printf("學生學號:%d\n",str1->student_num);
		
			printf("學生姓名:%s\n",str1->name);
			
			printf("學生性別:%s\n",str1->sex);
			
			printf("學生年齡:%d\n",str1->age);
		}
	}		
	else
	{
		ret = 0;
	}
	return ret;
}

int destroy_student(SeqList* slist, str* str1)
{
	int ret=(NULL != str1);
	int i=0;
	if(1 == ret)
	{
		for(i=0; i<Get_Seqlist_Length(slist); i++)
		{
			str1 = (str*)Get_Node(slist, i);
			free(str1);
		}
	}		
	else
	{
		ret = 0;
	}
	return ret;
}

int find_student(SeqList* slist, str* str1, int age)
{
	int ret=(NULL != str1);
	int i=0;
	int num=0;
	if(1 == ret)
	{
		num=Get_Seqlist_Length(slist);
		for(i=0; i<num; i++)
		{
			str1 = (str*)Get_Node(slist, i);
			if(str1->age == age)
			{
				Del_Node(slist, i);
				num=Get_Seqlist_Length(slist);
				i--;
			}
		}
	}		
	else
	{
		ret = 0;
	}
	return ret;
}