1. 線性表的定義和特點(diǎn)
線性表:由(n>=0)個(gè)數(shù)據(jù)特性相同的元素構(gòu)成的有限序列吩坝。
-
對(duì)于非空的線性表和線性結(jié)構(gòu),其特點(diǎn)如下:
- 存在唯一的一個(gè)被稱作"第一個(gè)"的數(shù)據(jù)元素
- 存在唯一的一個(gè)被稱作"最后一個(gè)"的數(shù)據(jù)元素
- 除了第一個(gè)之外艇抠,結(jié)構(gòu)中的每個(gè)數(shù)據(jù)元素均有一個(gè)前驅(qū)
- 除了最后一個(gè)之外,結(jié)構(gòu)中的每個(gè)數(shù)據(jù)元素都有一個(gè)后繼
線性表中的元素的個(gè)數(shù)n定義為線性表的長度,如果n = 0則稱為空表蹋偏。
1.1 線性表的類型定義
ADT List{
Data: 線性表的數(shù)據(jù)對(duì)象集合為{a1,a2,......an}尝偎,每個(gè)元素的類型均為DataType饶火。
除了第一個(gè)元素a1外,每一個(gè)元素有且只有一個(gè)直接前驅(qū)元素致扯。
除了最后一個(gè)元素an外肤寝,每個(gè)元素有且只有一個(gè)直接后繼元素。
數(shù)據(jù)元素之間的關(guān)系是一對(duì)一的關(guān)系抖僵。
Operation
InitList(&L)
操作結(jié)果:初始化操作鲤看,建立一個(gè)空的線性表L.
DestroyList(&L)
初始條件: 線性表L已存在
操作結(jié)果: 銷毀線性表L.
ClearList(&L)
初始條件: 線性表L已存在
操作結(jié)果: 將L重置為空表.
ListEmpty(L)
初始條件: 線性表L已存在
操作結(jié)果: 若L為空表,則返回true耍群,否則返回false.
ListLength(L)
初始條件: 線性表L已存在
操作結(jié)果: 返回L中數(shù)據(jù)元素的個(gè)數(shù)
GetElem(L义桂,i,&e)
初始條件: 線性表L已存在蹈垢,且1<=i<ListLength(L)
操作結(jié)果: 用e返回L中第i個(gè)數(shù)據(jù)元素的值;
LocateElem(L慷吊,e)
初始條件: 線性表L已存在
操作結(jié)果: 返回L中第1個(gè)值與e相同的元素在L中的位置. 若數(shù)據(jù)不存在則返回0;
PriorElem(L,cur_e曹抬,&pre_e);
初始條件: 線性表L已存在
操作結(jié)果: 若cur_e是L的數(shù)據(jù)元素溉瓶,且不是第一個(gè),則用pre_e返回其前驅(qū),否則操作失敗.
NextElem(L堰酿,cur_e疾宏,&next_e);
初始條件: 線性表L已存在
操作結(jié)果: 若cur_e是L的數(shù)據(jù)元素,且不是最后一個(gè)触创,則用next_e返回其后繼灾锯,否則操作失敗.
ListInsert(L,i嗅榕,e);
初始條件: 線性表L已存在顺饮,且1<=i<=listLength(L)
操作結(jié)果: 在L中第i個(gè)位置之前插入新的數(shù)據(jù)元素e,L長度加1.
ListDelete(L凌那,i);
初始條件: 線性表L已存在兼雄,且1<=i<=listLength(L)
操作結(jié)果: 刪除L的第i個(gè)元素,L的長度減1.
TraverseList(L);
初始條件: 線性表L已存在
操作結(jié)果: 對(duì)線性表L進(jìn)行遍歷帽蝶,在遍歷的過程中對(duì)L的每個(gè)結(jié)點(diǎn)訪問1次.
} ADT List;
2. 順序表
2.1 結(jié)構(gòu)設(shè)計(jì)
#define MAXSIZE 10
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define NOT_FOUND -1
/* ElemType類型根據(jù)實(shí)際情況而定赦肋,這里假設(shè)為int */
typedef int ElemType;
/* Status是函數(shù)的類型,其值是函數(shù)結(jié)果狀態(tài)代碼,如OK等 */
typedef int Status;
/*線性結(jié)構(gòu)使用順序表的方式存儲(chǔ)*/
//順序表結(jié)構(gòu)設(shè)計(jì)
typedef struct {
ElemType *datas;
int length;
} SqList;
2.2 方法實(shí)現(xiàn)
//1.1 順序表初始化
Status InitList(SqList *L)
{
// 為順序表分配一個(gè)大小為MAXSIZE的數(shù)組空間
L->datas = (ElemType *)malloc(sizeof(ElemType) * MAXSIZE);
// 存儲(chǔ)分配失敗退出
if (!L->datas) exit(ERROR);
//空表長度為0
L->length = 0;
return OK;
}
//1.2 順序表的取值
Status GetElem(SqList L, int idx, ElemType *elem)
{
//判斷i值是否合理励稳,若不合理佃乘,返回ERROR
if (idx < 0
|| idx > L.length) {
return ERROR;
}
*elem = L.datas[idx];
return OK;
}
//1.3 順序輸出List
Status TraverseList(SqList L)
{
for (int i = 0; i < L.length; i++)
printf("%d ", L.datas[i]);
printf("\n");
return OK;
}
//1.4 順序表的插入
Status InsertList(SqList *L, int idx, ElemType elem)
{
//idx值不合法判斷
if (idx < 0
|| idx > L->length
|| L->length == MAXSIZE) { //存儲(chǔ)空間已滿
return ERROR;
}
// 插入數(shù)據(jù)不在表尾,則先移動(dòng)出空余位置
if (idx < L->length) {
// 插入位置以及之后的位置后移動(dòng)1位
for (int i = L->length; i > idx; i--)
L->datas[i] = L->datas[i-1];
}
// 將新元素elem放入第idx個(gè)位置上
L->datas[idx] = elem;
// 長度+1
++L->length;
return OK;
}
//1.5 順序表的刪除
Status ListDelete(SqList *L, int idx) {
if (L->length == 0 //空表
|| idx < 0 //idx值不合法判斷
|| idx > L->length) {
return ERROR;
}
if (idx < L->length) {
// 被刪除元素之后的元素向前移動(dòng)
for (int i = idx + 1; i < L->length; i++)
L->datas[i-1] = L->datas[i];
}
// 長度-1
--L->length;
return OK;
}
//1.6 清空順序表
Status ClearList(SqList *L)
{
L->length=0;
return OK;
}
//1.7 判斷順序表清空
Status ListEmpty(SqList L)
{
return L.length == 0;
}
//1.8 獲取順序表長度
int ListLength(SqList L)
{
return L.length;
}
//1.9 順序表查找元素并返回位置
int LocateElem(SqList L, ElemType elem)
{
int i;
// 循環(huán)比較
for (i = 0; i < L.length; i++)
if (L.datas[i] == elem)
return i;
// 表里面沒找到
return NOT_FOUND;
}
int main(int argc, const char * argv[]) {
SqList L;
//初始化
if (InitList(&L)) {
printf("Init OK.\n");
}
//插入數(shù)據(jù)
for (int i = 0; i < MAXSIZE; i++) {
if (InsertList(&L, i, i) == ERROR) {
printf("insert ERROR.\n");
}
}
//遍歷
TraverseList(L);
//獲取第5個(gè)元素
ElemType elem;
GetElem(L, 5, &elem);
printf("5th: %d\n", elem);
//刪除第5個(gè)元素
ListDelete(&L, 5);
TraverseList(L);
int loc = LocateElem(L, 6);
if (loc != NOT_FOUND) {
printf("6 is %dth element\n", loc);
}
return 0;
}
主函數(shù):
int main(int argc, const char * argv[]) {
SqList L;
//初始化
if (InitList(&L)) {
printf("Init OK.\n");
}
//插入數(shù)據(jù)
for (int i = 0; i < MAXSIZE; i++) {
if (InsertList(&L, i, i) == ERROR) {
printf("insert ERROR.\n");
}
}
//遍歷
TraverseList(L);
//獲取第5個(gè)元素
ElemType elem;
GetElem(L, 5, &elem);
printf("5th: %d\n", elem);
//刪除第5個(gè)元素
ListDelete(&L, 5);
TraverseList(L);
int loc = LocateElem(L, 6);
if (loc != NOT_FOUND) {
printf("6 is %dth element\n", loc);
}
return 0;
}
// 輸出
Init OK.
0 1 2 3 4 5 6 7 8 9
5th: 5
0 1 2 3 4 6 7 8 9
6 is 5th element
Program ended with exit code: 0
3. 鏈表
3.1 結(jié)構(gòu)設(shè)計(jì)
#define MAXSIZE 10
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define NOT_FOUND -1
/* ElemType類型根據(jù)實(shí)際情況而定,這里假設(shè)為int */
typedef int ElemType;
/* Status是函數(shù)的類型,其值是函數(shù)結(jié)果狀態(tài)代碼驹尼,如OK等 */
typedef int Status;
/*線性結(jié)構(gòu)使用順序表的方式存儲(chǔ)*/
//鏈表結(jié)構(gòu)設(shè)計(jì)
typedef struct Node {
ElemType data;
struct Node *next;
} Node;
3.2 方法實(shí)現(xiàn)
//1.1 初始化單鏈表線性表
Status InitList(LinkList *L)
{
//產(chǎn)生頭結(jié)點(diǎn),并使用L指向此頭結(jié)點(diǎn)
*L = (LinkList)malloc(sizeof(Node));
//存儲(chǔ)空間分配失敗
if (*L == NULL) return ERROR;
//將頭結(jié)點(diǎn)的指針域置空
(*L)->next = NULL;
return OK;
}
//1.2 單鏈表的取值
Status GetElem(LinkList L, int idx, ElemType *elem)
{
// 用來計(jì)數(shù)
int i = 0;
// 聲明一個(gè)節(jié)點(diǎn)趣避,指向頭結(jié)點(diǎn)的下一個(gè)
LinkList p = L->next;
// p不為空,且i小于idx,則循環(huán)繼續(xù)
while (p && i < idx) {
p = p->next;
i++;
}
//如果p為空或者i>idx,則返回error
if(!p || i > idx) return ERROR;
//elem = p所指的結(jié)點(diǎn)的data
*elem = p->data;
return OK;
}
//1.3 順序輸出單鏈表
Status ListTraverse(LinkList L)
{
// 聲明一個(gè)節(jié)點(diǎn)新翎,指向頭結(jié)點(diǎn)的下一個(gè)
LinkList p = L->next;
while (p) {
printf("%d ",p->data);
p = p->next;
}
printf("\n");
return OK;
}
//1.4 單表的插入
Status ListInsert(LinkList *L, int idx, ElemType elem)
{
int i = 0;
LinkList p, s;
// 尋找第idx-1個(gè)結(jié)點(diǎn)程帕,所以這里指向表頭
p = *L;
while (p && i < idx) {
p = p->next;
i++;
}
// 第idx個(gè)元素不存在
if(!p || i > idx) return ERROR;
// 創(chuàng)建新節(jié)點(diǎn)
s = (LinkList)malloc(sizeof(Node));
s->data = elem;
//將p的后繼結(jié)點(diǎn)賦值給s的后繼
s->next = p->next;
//將s賦值給p的后繼
p->next = s;
return OK;
}
//1.5 單鏈表刪除元素
Status ListDelete(LinkList *L, int idx, ElemType *elem)
{
int i = 0;
LinkList p, q;
// 尋找第idx-1個(gè)結(jié)點(diǎn),所以這里指向表頭
p = *L;
while (p && i < idx) {
p = p->next;
i++;
}
// 第idx個(gè)元素不存在
if(!p || i > idx) return ERROR;
// q指向要?jiǎng)h除的結(jié)點(diǎn)
q = p->next;
// 將q的后繼賦值給p的后繼
p->next = q->next;
// 將q結(jié)點(diǎn)中的數(shù)據(jù)給elem
*elem = q->data;
// 釋放被刪除節(jié)點(diǎn)
free(q);
return OK;
}
//1.6 清空單鏈表
Status ClearList(LinkList *L)
{
LinkList p, q;
// 從表頭下一個(gè)開始刪
p = (*L)->next;
// 清空表頭地啰,防止野指針
(*L)->next = NULL;
while(p) {
// q指向要?jiǎng)h除的結(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
q = p->next;
// 釋放被刪除節(jié)點(diǎn)
free(p);
// p變?yōu)橄乱粋€(gè)節(jié)點(diǎn)
p = q;
}
return OK;
}
//1.7 判斷順序表清空
Status ListEmpty(LinkList L)
{
return L->next == NULL;
}
//1.8 獲取順序表長度
int ListLength(LinkList L)
{
int i = 0;
LinkList p = L;
while (p) {
p = p->next;
i++;
}
return i;
}
//1.9 順序表查找元素并返回位置
int LocateElem(LinkList L, ElemType elem)
{
if (L->next == NULL) return NOT_FOUND;
int i = 0;
LinkList p = L->next;
while (p) {
if (p->data == elem) {
return i;
}
p = p->next;
i++;
}
return NOT_FOUND;
}
主函數(shù):
int main(int argc, const char * argv[]) {
LinkList L;
ElemType elem;
//初始化
if (InitList(&L)) {
printf("Init OK.\n");
}
//插入數(shù)據(jù)
for (int i = 0; i < MAXSIZE; i++) {
if (ListInsert(&L, i, i) == ERROR) {
printf("insert ERROR.\n");
}
}
//遍歷
ListTraverse(L);
//獲取第6個(gè)元素
GetElem(L, 5, &elem);
printf("6th: %d\n", elem);
//刪除第6個(gè)元素
ListDelete(&L, 5, &elem);
//遍歷
ListTraverse(L);
int loc = LocateElem(L, 6);
if (loc != NOT_FOUND) {
printf("6 is at %d\n", loc);
}
return 0;
}
// 輸出
Init OK.
0 1 2 3 4 5 6 7 8 9
6th: 5
0 1 2 3 4 6 7 8 9
6 is at 5
Program ended with exit code: 0
3.3 初始化頭插法
新節(jié)點(diǎn)插入到頭結(jié)點(diǎn)之后:
void CreateListHead(LinkList *L, int n){
// 生成頭結(jié)點(diǎn)
*L = (LinkList)malloc(sizeof(Node));
(*L)->next = NULL;
// 循環(huán)前插入隨機(jī)數(shù)據(jù)
LinkList p;
for (int i = 0; i < n; i++) {
p = (LinkList)malloc(sizeof(Node));
p->data = i;
// 新節(jié)點(diǎn)指向頭結(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
p->next = (*L)->next;
// 頭結(jié)點(diǎn)指向新節(jié)點(diǎn)
(*L)->next = p;
}
}
3.4 初始化尾插法
新節(jié)點(diǎn)插入到最后:
void CreateListTail(LinkList *L, int n)
{
LinkList p, r;
// 建立1個(gè)帶頭結(jié)點(diǎn)的單鏈表
*L = (LinkList)malloc(sizeof(Node));
//r指向尾部的結(jié)點(diǎn)
r = *L;
// 循環(huán)尾插入隨機(jī)數(shù)據(jù)
for (int i = 0; i < n; i++) {
p = (Node *)malloc(sizeof(Node));
p->data = i;
// 尾節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)指向新節(jié)點(diǎn)
r->next = p;
// r指向當(dāng)前的尾節(jié)點(diǎn)
r = p;
}
// 插入完畢愁拭,尾節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)應(yīng)該為NULL
r->next = NULL;
}