線性表的定義:N個數據元素的有限序列
線性表從存儲結構上分爲:順序存儲結構(數組)和 鏈式存儲結構(鏈表)
順序存儲結構:是用一段連續的內存空間存儲表中的數據 L=(a1,a2,a3….an)
鏈式存儲結構:是用一段一段連續的內存空間存儲表中每一行的數據,段與段之間通過一個引用(指針)相互連接來,形成一個鏈式的存儲結構
看到順序存儲結構的圖示,我們可能會馬上聯想到C語言的數組。是的,數組就是一種典型的順序存儲數據結構。下面我通過一個實例,來實現對順序存儲結構中的數據增、刪、改、查的操作。
首先定一個描述線性表數據的順序存儲結構:
// 默認增長因子
#define DEFAULT_CAPACITY 10
typedef unsigned int * PU32;
typedef unsigned int U32;
/************************************************************************/
/* 線性表數據結構,存儲數組元素、數組大小、數組增長因子,下面簡稱爲動態數組 */
/************************************************************************/
typedef struct _tag_ArrayList
{
PU32 container; // 存儲數組元素的容器
int length; // 數組長度
int capacity; // 數組增長因子
} TArrayList;
container:是一個無符號32位的指針數組,用於存儲線性表中的所有元素,後面的增、刪、改查都是操作這個操作中指針元素
length:記錄數組中的元數數量,表示這個線性表中存儲了多少個數據元素
capacity:因爲要實現數組動態擴容的功能,這個值代表數組滿後,每次擴容的大小,默認爲10
線性表初始化
[cpp] view plain copy 在CODE上查看代碼片派生到我的代碼片
ArrayList * ArrayList_CreateDefault()
{
return ArrayList_Create(DEFAULT_CAPACITY);
}
ArrayList * ArrayList_Create(int capacity)
{
if (capacity < 0)
{
printf("fun ArrayList_Create error, Illegal capacity: %d", capacity);
return NULL;
}
TArrayList *list = (TArrayList *)malloc(sizeof(TArrayList));
if (list == NULL)
{
printf("out of memory, create ArrayList fail!");
return NULL;
}
list->capacity = capacity;
list->length = 0;
list->container = (PU32)malloc(sizeof(PU32)* DEFAULT_CAPACITY);
if (list->container == NULL)
{
printf("out of memory, create Array container fail!");
return NULL;
}
memset(list->container, 0, sizeof(PU32)* DEFAULT_CAPACITY);
return list;
}
ArrayList_CreateDefault:初始化默認10個元素大小的線性表存儲空間
ArrayList_Create:根據capacity大小初始化
其中ArrayList是通過typedef void定義的一個類型,因爲想屏蔽內部實現線性表的數據存儲結構,使用者無須關注裏面的實現細節,只需保存這個線性表句柄的引用,當每次操作線性表時,都將這個句柄作爲形參傳給相應的函數即可。
往線性表中指定位置添加元素
int ArrayList_AddItem(ArrayList *list, ArrayItem *item, int pos)
{
int ret = 0;
TArrayList *arrayList = NULL;
if (list == NULL || item == NULL)
{
ret = -1;
printf("fun ArrayList_AddItem error:%d of the list is NULL or item is NULL\n", ret);
return ret;
}
arrayList = (TArrayList *)list;
// 容錯處理,如果當前存儲了3個元素,要在第5個位置插入一個元素,將插入位置改成第4個位置
// |0|1|2|3| | |
if (pos > arrayList->length)
{
pos = arrayList->length;
}
// 擴容
PU32 newContainer = NULL;
if (arrayList->length > 0 && arrayList->length % arrayList->capacity == 0)
{
newContainer = (PU32)malloc(sizeof(PU32)* (arrayList->length + arrayList->capacity));
if (newContainer == NULL)
{
ret = -2;
printf("out of memory, add item fail!");
return ret;
}
memset(newContainer, 0, arrayList->length * sizeof(PU32));
// 將舊的數據拷貝到新的容器中
memcpy(newContainer, arrayList->container, arrayList->length * sizeof(PU32));
// 釋放舊容器的內存
free(arrayList->container);
// 指向新容器的地址
arrayList->container = newContainer;
}
// 將元素插入到數組pos位置
for (int i = arrayList->length; i > pos; i--)
{
arrayList->container[i] = arrayList->container[i - 1];
}
arrayList->container[pos] = (U32)item;
arrayList->length++;
return ret;
}
1、添加前,首先判斷再添加一個元素後,數組是否會滿,如果會滿就先擴容
arrayList->length > 0 && arrayList->length % arrayList->capacity == 0
2、將元素插入到數組中指定的位置。如果當前數組中有5個元素,新元素要插入到數組的第3個位置,所以第3個位置和後面的元素都要往後移
for (int i = arrayList->length; i > pos; i–)
{
arrayList->Container[i] = arrayList->container[i - 1];
}
arrayList->container[pos] = (U32)item;
arrayList->length++; // 長度+1
刪除線性表中指定位置的元素(與添加相反)
ArrayItem * ArrayList_RemoveItem(ArrayList *list, int pos)
{
TArrayList *arrayList = NULL;
ArrayItem *arrayItem = NULL;
arrayList = checkRange(list, pos);
if (arrayList == NULL)
{
return NULL;
}
// 緩存刪除的元素
arrayItem = (ArrayItem *)arrayList->container[pos];
// 從數組中移徐指定索引的元素
for (int i = pos; i < arrayList->length; i++)
{
arrayList->container[i] = arrayList->container[i + 1];
}
arrayList->length--; // 長度減1
return arrayItem; // 返回被刪除的元素
}
刪除前首先保存要刪除的元素,刪除成功返回將該元素返回
還有其它操作(在表尾添加元素、獲取、遍歷、清除、銷燬等),這裏不一一講解了,源代碼中有詳細的註釋,下面給出完整的源代碼與測試用例:
// ArrayList.h
// 線性表存儲--動態數組
//
// Created by 楊信 on 14-5-15.
// Copyright (c) 2014年 yangxin. All rights reserved.
//
#ifndef __ArrayList_H__
#define __ArrayList_H__
#ifdef _cplusplus
extern "C" {
#endif
typedef void ArrayList; // 線性表句柄
typedef void ArrayItem; // 線性表的條目
/*
遍歷數組的回調函數
@item : 當前元素
@pos : 當前元素的索引
*/
typedef void(*_Each_Function)(ArrayItem *item, int pos);
/*
創建一個默認capacity大小的動態數組
capacity默認爲10
@return 動態數組句柄
*/
ArrayList * ArrayList_CreateDefault();
/*
創建一個初始化容量爲capacity大小的動態數組
@capacity : 數組大小增長因子,如果數組已滿,則自動增長capacity大小
@return 動態數組句柄
*/
ArrayList * ArrayList_Create(int capacity);
/*
在指定位置添加(插入)一個元素
@list : 動態數組句柄
@item : 新添加的數組元素
@pos : 插入位置(索引從0開始)
@return 插入成功返回0,失敗返回非0值
*/
int ArrayList_AddItem(ArrayList *list, ArrayItem *item, int pos);
/*
在數組某尾添加一個元素
@list : 動態數組句柄
@item : 新添加的數組元素
@return 插入成功返回0,失敗返回非0值
*/
int ArrayList_AddItemBack(ArrayList *list, ArrayItem *item);
/*
刪除一個數組元素
@list : 動態數組句柄
@pos : 插入位置(索引從0開始)
@return 刪除成功返回被刪除的元素,失敗返回NULL
*/
ArrayItem * ArrayList_RemoveItem(ArrayList *list, int pos);
/*
清空數組所有元素
@list : 動態數組句柄
@return 成功返回0,失敗返回非0值
*/
int ArrayList_Clear(ArrayList *list);
/*
修改數組元素
@list : 動態數組句柄
@item : 新元素
@pos : 修改元素的索引
@return 修改成功返回0,失敗返回非0值
*/
int ArrayList_SetItem(ArrayList *list, ArrayItem *item, int pos);
/*
獲取數組指定位置的元素
@list : 動態數組句柄
@pos : 元素索引
@return 返回數組指定位置的元素,如果pos大於等於數組長度或小於0,則返回NULL
*/
ArrayItem * ArrayList_GetItem(ArrayList *list, int pos);
/*
遍歷數組
@list : 動態數組句柄
@_fun_callback : 遍歷數組中每個元素時的回調函數
函數原型:void(*_Each_Function)(ArrayItem *item, int pos);
示例:void ArrayEachCallback(ArrayItem *item, int pos) { ... }
*/
void ArrayList_For_Each(ArrayList *list, _Each_Function _fun_callback);
/*
遍歷數組指定範圍內的元素
@list : 動態數組句柄
@begin : 元素開始位置
@end : 元素結束位置
@_fun_callback : 遍歷數組中每個元素時的回調函數
函數原型:void(*_Each_Function)(ArrayItem *item, int pos);
示例:void ArrayEachCallback(ArrayItem *item, int pos) { ... }
*/
void ArrayList_For_Each_Range(ArrayList *list, int begin, int end,
_Each_Function _fun_callback);
/*
獲取動態數組的長度(存儲的元素數量)
@list : 動態數組句柄
@return 數組長度
*/
int ArrayList_GetLength(ArrayList * list);
/*
獲取動態數組的增長因子
@list : 動態數組句柄
@return 數組增長因子
*/
int ArrayList_GetCapacity(ArrayList * list);
/*
銷燬動態數組(釋放內存)
@list : 動態數組句柄
@return 銷燬成功返回0,失敗返回非0值
*/
int ArrayList_Destory(ArrayList **list);
#ifdef _cplusplus
}
#endif
#endif
//
// ArrayList.c
// 線性表存儲--動態數組
//
// Created by 楊信 on 14-5-15.
// Copyright (c) 2014年 yangxin. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ArrayList.h"
// 默認增長因子
#define DEFAULT_CAPACITY 10
typedef unsigned int * PU32;
typedef unsigned int U32;
/************************************************************************/
/* 線性表數據結構,存儲數組元素、數組大小、數組增長因子,下面簡稱爲動態數組 */
/************************************************************************/
typedef struct _tag_ArrayList
{
PU32 container; // 存儲數組元素的容器
int length; // 數組長度
int capacity; // 數組增長因子
} TArrayList;
// 檢查索引範圍
static TArrayList * checkRange(ArrayList *list, int pos);
ArrayList * ArrayList_CreateDefault()
{
return ArrayList_Create(DEFAULT_CAPACITY);
}
ArrayList * ArrayList_Create(int capacity)
{
if (capacity < 0)
{
printf("fun ArrayList_Create error, Illegal capacity: %d", capacity);
return NULL;
}
TArrayList *list = (TArrayList *)malloc(sizeof(TArrayList));
if (list == NULL)
{
printf("out of memory, create ArrayList fail!");
return NULL;
}
list->capacity = capacity;
list->length = 0;
list->container = (PU32)malloc(sizeof(PU32)* DEFAULT_CAPACITY);
if (list->container == NULL)
{
printf("out of memory, create Array container fail!");
return NULL;
}
memset(list->container, 0, sizeof(PU32)* DEFAULT_CAPACITY);
return list;
}
int ArrayList_AddItem(ArrayList *list, ArrayItem *item, int pos)
{
int ret = 0;
TArrayList *arrayList = NULL;
if (list == NULL || item == NULL)
{
ret = -1;
printf("fun ArrayList_AddItem error:%d of the list is NULL or item is NULL\n", ret);
return ret;
}
arrayList = (TArrayList *)list;
// 容錯處理,如果當前存儲了3個元素,要在第5個位置插入一個元素,將插入位置改成第4個位置
// |0|1|2|3| | |
if (pos > arrayList->length)
{
pos = arrayList->length;
}
// 擴容
PU32 newContainer = NULL;
if (arrayList->length > 0 && arrayList->length % arrayList->capacity == 0)
{
newContainer = (PU32)malloc(sizeof(PU32)* (arrayList->length + arrayList->capacity));
if (newContainer == NULL)
{
ret = -2;
printf("out of memory, add item fail!");
return ret;
}
memset(newContainer, 0, arrayList->length * sizeof(PU32));
// 將舊的數據拷貝到新的容器中
memcpy(newContainer, arrayList->container, arrayList->length * sizeof(PU32));
// 釋放舊容器的內存
free(arrayList->container);
// 指向新容器的地址
arrayList->container = newContainer;
}
// 將元素插入到數組pos位置
for (int i = arrayList->length; i > pos; i--)
{
arrayList->container[i] = arrayList->container[i - 1];
}
arrayList->container[pos] = (U32)item;
arrayList->length++; // 長度+1
return ret;
}
int ArrayList_AddItemBack(ArrayList *list, ArrayItem *item)
{
int ret = 0;
TArrayList *arrayList = NULL;
if (list == NULL || item == NULL)
{
ret = -1;
printf("fun ArrayList_AddItemBack error:%d, of the list or item is NULL.\n");
return ret;
}
arrayList = (TArrayList *)list;
return ArrayList_AddItem(list, item, arrayList->length);
}
ArrayItem * ArrayList_RemoveItem(ArrayList *list, int pos)
{
TArrayList *arrayList = NULL;
ArrayItem *arrayItem = NULL;
arrayList = checkRange(list, pos);
if (arrayList == NULL)
{
return NULL;
}
// 緩存刪除的元素
arrayItem = (ArrayItem *)arrayList->container[pos];
// 從數組中移徐指定索引的元素
for (int i = pos; i < arrayList->length; i++)
{
arrayList->container[i] = arrayList->container[i + 1];
}
arrayList->length--; // 長度減1
return arrayItem; // 返回被刪除的元素
}
int ArrayList_Clear(ArrayList *list)
{
int ret = 0;
TArrayList *arrayList = NULL;
if (list == NULL)
{
ret = -1;
printf("fun ArrayList_Clear error:%d, of the list is NULL.\n");
return ret;
}
arrayList = (TArrayList *)list;
while (arrayList->length)
{
arrayList->container[--arrayList->length] = 0;
}
return 0;
}
int ArrayList_SetItem(ArrayList *list, ArrayItem *item, int pos)
{
int ret = 0;
TArrayList *arrayList = NULL;
arrayList = checkRange(list, pos);
if (arrayList == NULL || item == NULL)
{
ret = -1;
printf("fun ArrayList_SetItem error:%d, of the list or item is NULL.\n",ret);
return ret;
}
arrayList->container[pos] = (U32)item;
return 0;
}
ArrayItem * ArrayList_GetItem(ArrayList *list, int pos)
{
TArrayList *arrayList = NULL;
arrayList = checkRange(list, pos);
if (arrayList == NULL)
{
return NULL;
}
return (ArrayItem *)arrayList->container[pos];
}
void ArrayList_For_Each(ArrayList *list, _Each_Function _fun_callback)
{
TArrayList *arrayList = NULL;
if (list == NULL || _fun_callback == NULL)
{
printf("fun ArrayList_For_Each error, list or _fun_callback is NULL.\n");
return;
}
arrayList = (TArrayList *)list;
for (int i = 0; i < arrayList->length; i++)
{
_fun_callback((ArrayItem *)arrayList->container[i], i);
}
};
void ArrayList_For_Each_Range(ArrayList *list, int begin, int end,
_Each_Function _fun_callback)
{
TArrayList *arrayList = NULL;
if (list == NULL || _fun_callback == NULL)
{
printf("fun ArrayList_For_Each_Range error, list or _fun_callback is NULL.\n");
return;
}
arrayList = (TArrayList *)list;
if ((begin < 0 || begin > end) ||
(end >= arrayList->length || end < begin))
{
printf("fun ArrayList_For_Each_Range error, pos out range:%d-%d", begin, end);
return;
}
for (int i = begin; i < end; i++)
{
_fun_callback((ArrayItem *)arrayList->container[i], i);
}
};
int ArrayList_GetLength(ArrayList * list)
{
TArrayList *arrayList = NULL;
if (list == NULL)
{
printf("fun ArrayList_GetLength error, list is NULL.\n");
return -1;
}
arrayList = (TArrayList *)list;
return arrayList->length;
}
int ArrayList_GetCapacity(ArrayList * list)
{
TArrayList *arrayList = NULL;
if (list == NULL)
{
printf("fun ArrayList_GetCapacity error, list is NULL.\n");
return -1;
}
arrayList = (TArrayList *)list;
return arrayList->capacity;
}
int ArrayList_Destory(ArrayList **list)
{
int ret = 0;
if (list == NULL)
{
ret = -1;
printf("fun ArrayList_Destory error:%d from (list == NULL)\n", ret);
return ret;
}
TArrayList *arrayList = (TArrayList *)*list;
if (arrayList->container != NULL)
{
free(arrayList->container);
arrayList->container = NULL;
}
free(arrayList);
*list = NULL;
return ret;
}
static TArrayList * checkRange(ArrayList *list, int pos)
{
TArrayList *arrayList = NULL;
if (list == NULL)
{
printf("fun checkRange error, of the list is NULL.\n");
return NULL;
}
arrayList = (TArrayList *)list;
if (pos < 0 || pos >= arrayList->length)
{
printf("fun checkRange error, of the pos:%d out range.\n", pos);
return NULL;
}
return arrayList;
}
//-------------------------測試用例--------------------------------//
#include <stdio.h>
#include <stdlib.h>
#include "ArrayList.h"
typedef struct Person {
int age;
char name[20];
}Person;
void EachArrayCallback(ArrayItem *item, int pos)
{
Person *p = (Person *)item;
printf("%d-->age=%d\n",pos,p->age);
}
void main1()
{
int ret = -65535;
ArrayList *list = NULL;
list = ArrayList_Create(2);
Person p1, p2, p3, p4, p5,p6,p7,p8;
p1.age = 10;
p2.age = 20;
p3.age = 30;
p4.age = 40;
p5.age = 50;
p6.age = 60;
p7.age = 70;
p8.age = 80;
//ArrayList_AddItem(list, 100, 7);
ArrayList_AddItem(list, &p1, 0);
ArrayList_AddItem(list, &p2, 0);
ArrayList_AddItem(list, &p3, 0);
ArrayList_AddItem(list, &p4, 0);
ArrayList_AddItem(list, &p5, 0);
ArrayList_AddItem(list, &p6, 0);
ArrayList_AddItemBack(list, &p7);
ArrayList_AddItemBack(list, &p8);
printf("數組長度:%d\n", ArrayList_GetLength(list));
ArrayItem *item = ArrayList_RemoveItem(list, 2);
printf("刪除索引2位置的元素:%d\n",((Person *)item)->age);
for (int i = 0; i < ArrayList_GetLength(list); i++)
{
Person *p = (Person *)ArrayList_GetItem(list, i);
printf("age=%d\n", p->age);
}
Person pp = {100,"zhangsan"};
ArrayList_SetItem(list, &pp, 1); // 修改索引位置爲1的元素
Person *p = (Person *)ArrayList_GetItem(list,1);
if (p != NULL)
{
printf("age=%d\n",p->age);
}
printf("\n---------------------foreach回調函數遍歷數組------------------\n");
ArrayList_For_Each(list, EachArrayCallback);
// 遍歷指定範圍內的元素
printf("\n---------------foreach遍歷指定範圍內的數組元素------------------\n");
ArrayList_For_Each_Range(list, 2, 5, EachArrayCallback);
// 清徐數組所有元素
ret = ArrayList_Clear(list);
printf("arraylist length: %d\n", ArrayList_GetLength(list));
ret = ArrayList_Destory(&list);
system("pause");
}
void fun(ArrayItem *item, int pos)
{
printf("%d--%d\n",pos,(unsigned int)item);
}
void main()
{
ArrayList *list = NULL;
list = ArrayList_Create(5);
ArrayList_AddItem(list, (ArrayItem *)10, 0);
ArrayList_AddItem(list, (ArrayItem *)20, 0);
ArrayList_AddItem(list, (ArrayItem *)30, 0);
ArrayList_AddItem(list, (ArrayItem *)40, 0);
ArrayList_AddItem(list, (ArrayItem *)50, 0);
ArrayList_AddItemBack(list, (ArrayItem *)60);
printf("delete-->%d\n",(unsigned int)ArrayList_RemoveItem(list, 0));
ArrayList_For_Each(list, fun);
ArrayList_Destory(&list);
system("pause");
}