1、線性表的定義
線性表(Linear List):由同類型的數據元素構成的有序序列的線性結構:表中元素個數稱爲線性表的長度,線性表沒有元素時,稱爲空表,表起始位置稱表頭,表結束位置稱爲表尾。
2、鏈表的順序存儲的實現
2.1 數據結構表示
利用數組的連續存儲空間順序存放線性表的各元素。首先定義鏈表的基本數據結構如下所示:
/* 定義List的基本結構 */
#define MAXSIZE 10 // 鏈表的長度
typedef int ElementType;
typedef struct _List{
ElementType Data[MAXSIZE];
int Last; // 鏈表中最後一個元素的下標
} List;
2.2 創建一個空鏈表
/* 初始化一個鏈表,即構造一個空表 */
List *MakeEmpty( )
{
List *PtrL;
PtrL = (List *)malloc( sizeof(List) );
PtrL->Last = -1;
return PtrL;
}
2.3 插入操作
/* 插入操作:在第i個位置上插入一個元素X */
void Insert( ElementType X, int i, List *PtrL )
{
int j = 0;
if ( PtrL->Last == MAXSIZE-1 )
{
/* 表空間已滿,不能插入*/
printf("Table is full!\n");
return;
}
if ( i < 1 || i > PtrL->Last+2)
{
/*檢查插入位置的合法性*/
printf("The position of insert is illegal!\n");
return;
}
for ( j = PtrL->Last; j >= i-1; j-- )
PtrL->Data[j+1] = PtrL->Data[j]; /*將 ai~an倒序向後移動*/
PtrL->Data[i-1] = X; /*新元素插入*/
PtrL->Last++; /*Last仍指向最後元素*/
return;
}
2.4 刪除操作
/* 刪除表第i個元素 */
void Delete( int i, List *PtrL )
{
int j = 0;
if( i < 1 || i > PtrL->Last+1 )
{
/*檢查空表及刪除位置的合法性*/
printf ("The position of delete is illegal!\n");
return ;
}
for ( j = i; j <= PtrL->Last; j++ )
PtrL->Data[j-1] = PtrL->Data[j]; /*將 ai+1~ an順序向前移動*/
PtrL->Last--; /*Last仍指向最後元素*/
return;
}
2.5 查找操作
/** 查找:按指定元素來查找
* X 要查找的元素值
* PtrL 要查找的鏈表的頭結點指針
* 返回值 對應元素的下標
*/
int Find( ElementType X, List *PtrL )
{
int i = 0;
while( i <= PtrL->Last && PtrL->Data[i]!= X )
i++;
if (i > PtrL->Last) return -1; /* 如果沒找到,返回-1 */
else return i; /* 找到後返回的是存儲位置 */
}
2.6 修改操作
/* 修改元素值 */
void Change( ElementType X, int i, List *PtrL)
{
if ( i < 1 || i > PtrL->Last+1)
{
/*檢查插入位置的合法性*/
printf("The position of change is illegal!\n");
return;
}
PtrL->Data[i - 1] = X; /* 對要修改的元素進行賦值 */
}
2.7 完整的示例代碼
/** 線性表的順序存儲
* Date : 2017-09-10
*/
#include <stdio.h>
#include <stdlib.h>
/* 定義List的基本結構 */
#define MAXSIZE 10 // 鏈表的長度
typedef int ElementType;
typedef struct _List{
ElementType Data[MAXSIZE];
int Last; // 鏈表中最後一個元素的下標
} List;
/* 初始化一個鏈表,即構造一個空表 */
List *MakeEmpty( )
{
List *PtrL;
PtrL = (List *)malloc( sizeof(List) );
PtrL->Last = -1;
return PtrL;
}
/* 銷燬一個鏈表,釋放內存空間 */
void MakeDestroy(List *PtrL)
{
if(PtrL != NULL) free(PtrL);
PtrL = NULL;
}
/** 查找:按指定元素來查找
* X 要查找的元素值
* PtrL 要查找的鏈表的頭結點指針
* 返回值 對應元素的下標
*/
int Find( ElementType X, List *PtrL )
{
int i = 0;
while( i <= PtrL->Last && PtrL->Data[i]!= X )
i++;
if (i > PtrL->Last) return -1; /* 如果沒找到,返回-1 */
else return i; /* 找到後返回的是存儲位置 */
}
/* 插入操作:在第i個位置上插入一個元素X */
void Insert( ElementType X, int i, List *PtrL )
{
int j = 0;
if ( PtrL->Last == MAXSIZE-1 )
{
/* 表空間已滿,不能插入*/
printf("Table is full!\n");
return;
}
if ( i < 1 || i > PtrL->Last+2)
{
/*檢查插入位置的合法性*/
printf("The position of insert is illegal!\n");
return;
}
for ( j = PtrL->Last; j >= i-1; j-- )
PtrL->Data[j+1] = PtrL->Data[j]; /*將 ai~an倒序向後移動*/
PtrL->Data[i-1] = X; /*新元素插入*/
PtrL->Last++; /*Last仍指向最後元素*/
return;
}
/* 刪除表第i個元素 */
void Delete( int i, List *PtrL )
{
int j = 0;
if( i < 1 || i > PtrL->Last+1 )
{
/*檢查空表及刪除位置的合法性*/
printf ("The position of delete is illegal!\n");
return ;
}
for ( j = i; j <= PtrL->Last; j++ )
PtrL->Data[j-1] = PtrL->Data[j]; /*將 ai+1~ an順序向前移動*/
PtrL->Last--; /*Last仍指向最後元素*/
return;
}
/* 修改元素值 */
void Change( ElementType X, int i, List *PtrL)
{
if ( i < 1 || i > PtrL->Last+1)
{
/*檢查插入位置的合法性*/
printf("The position of change is illegal!\n");
return;
}
PtrL->Data[i - 1] = X; /* 對要修改的元素進行賦值 */
}
/* 遍歷這個鏈表中的元素 */
void Traversal(List *PtrL)
{
int i = 0;
if((PtrL == NULL) || (PtrL->Last < 0))
{
printf("List is illegal!\n");
return ;
}
for(i = 0; i <= PtrL->Last; i++)
printf("%d ", PtrL->Data[i]);
printf("\n");
}
/* 返回線性表的長度 */
int Length(List *PtrL)
{
if(PtrL == NULL)
{
printf("List is illegal!\n");
return -1;
}
return PtrL->Last + 1;
}
/* 程序入口 */
int main()
{
int i, index;
ElementType temp;
List *list;
list = MakeEmpty(); /* 創建一個鏈表 */
/* 向鏈表中插入五個元素 */
printf("Input 5 numbers : ");
for(i = 0; i < 5; i++)
{
scanf("%d", &temp);
Insert(temp, i+1, list); // 注意這裏要插入的是第i個元素,而數組的下標是從零開始的,所以要加一
}
printf("************************************Traversal*****************************\n");
/* 打印鏈表中的元素 */
Traversal(list);
printf("Length = %d\n", Length(list));
printf("************************************Delete********************************\n");
/* 刪除一個元素 */
Delete(3, list);
Traversal(list);
printf("Length = %d\n", Length(list));
printf("************************************Insert********************************\n");
/* 插入一個元素 */
Insert(100, 2, list);
Traversal(list);
printf("Length = %d\n", Length(list));
printf("************************************Change********************************\n");
/* 插入一個元素 */
Change(888, 1, list);
Traversal(list);
printf("Length = %d\n", Length(list));
printf("************************************Find*********************************\n");
/* 查找一個元素 */
index = Find(100, list);
Traversal(list);
printf("Length = %d, Index = %d\n", Length(list), index);
MakeDestroy(list); /* 銷燬這個鏈表 */
return 0;
}
3、鏈表的鏈式存儲的實現
不要求邏輯上相鄰的兩個元素物理上也相鄰;通過鏈建立起數據元素之間的邏輯關係;插入、刪除不需要移動數據元素,只需要修改鏈。3.1 基本數據結構
/* 基本數據結構定義 */
typedef int ElementType;
typedef struct Node{
ElementType Data;
struct Node *Next;
} List;
3.2 插入操作
/* 在第i個結點位置上插入一個新結點 */
List *Insert( ElementType X, int i, List *PtrL )
{
List *p, *s;
if ( i == 1 )
{
/* 新結點插入在表頭 */
s = (List *)malloc(sizeof(List)); /*申請、填裝結點*/
s->Data = X;
s->Next = PtrL;
return s; /*返回新表頭指針*/
}
p = FindKth( i-1, PtrL ); /* 查找第i-1個結點 */
if ( p == NULL )
{
/* 第i-1個不存在,不能插入 */
printf("the node of i-1 is not exist!\n");
return NULL;
}
else
{
s = (List *)malloc(sizeof(List)); /*申請、填裝結點*/
s->Data = X;
s->Next = p->Next; /*新結點插入在第i-1個結點的後面*/
p->Next = s;
return PtrL;
}
}
3.3 刪除操作
/* 刪除第i個結點 */
List *Delete( int i, List *PtrL )
{
List *p, *s;
if ( i == 1 )
{
/* 若要刪除的是表的第一個結點 */
s = PtrL; /*s指向第1個結點*/
if (PtrL!=NULL) PtrL = PtrL->Next; /*從鏈表中刪除*/
else return NULL;
free(s); /*釋放被刪除結點 */
return PtrL;
}
p = FindKth( i-1, PtrL ); /*查找第i-1個結點*/
if ( p == NULL )
{
printf("the node of i-1 is not exist!\n"); return NULL;
}
else if ( p->Next == NULL )
{
printf("the node of i is not exist!\n"); return NULL;
}
else
{
s = p->Next; /*s指向第i個結點*/
p->Next = s->Next; /*從鏈表中刪除*/
free(s); /*釋放被刪除結點 */
return PtrL;
}
}
3.4 查找操作
查找操作實現了兩種:一種是按照元素值查找,還有一種是按照存在鏈表中的位置來查找具體實現如下:/* 查找鏈表中值爲X的元素 */
List *Find( ElementType X, List *PtrL )
{
List *p = PtrL;
while ( p!=NULL && p->Data != X )
p = p->Next;
return p;
}
按位置來查找:/* 查找鏈表中第K個元素 */
List *FindKth( int K, List *PtrL )
{
List *p = PtrL;
int i = 1;
while (p != NULL && i < K )
{
p = p->Next;
i++;
}
if ( i == K ) return p; /* 找到第K個,返回指針 */
else return NULL; /* 否則返回空 */
}
3.5 修改操作
/* 修改元素值 */
void Change( ElementType X, int i, List *PtrL)
{
List *p;
p = FindKth( i, PtrL ); /* 查找第i個結點 */
if ( p == NULL )
{
/* 第i-1個不存在,不能插入 */
printf("the node of i-1 is not exist!\n");
return ;
}
else
{
p->Data = X;
}
}
3.6 完整的示例代碼實現
/* 線性表的鏈式存儲 */
#include <stdio.h>
#include <stdlib.h>
/* 基本數據結構定義 */
typedef int ElementType;
typedef struct Node{
ElementType Data;
struct Node *Next;
} List;
/* 銷燬一個鏈表,釋放內存空間 */
void MakeDestroy(List *PtrL)
{
List *PtrTemp = PtrL;
List *PtrNext;
while(PtrTemp)
{
PtrNext = PtrTemp->Next;
free(PtrTemp);
PtrTemp = PtrNext;
}
}
/* 查找鏈表中第K個元素 */
List *FindKth( int K, List *PtrL )
{
List *p = PtrL;
int i = 1;
while (p != NULL && i < K )
{
p = p->Next;
i++;
}
if ( i == K ) return p; /* 找到第K個,返回指針 */
else return NULL; /* 否則返回空 */
}
/* 查找鏈表中值爲X的元素 */
List *Find( ElementType X, List *PtrL )
{
List *p = PtrL;
while ( p!=NULL && p->Data != X )
p = p->Next;
return p;
}
/* 在第i個結點位置上插入一個新結點 */
List *Insert( ElementType X, int i, List *PtrL )
{
List *p, *s;
if ( i == 1 )
{
/* 新結點插入在表頭 */
s = (List *)malloc(sizeof(List)); /*申請、填裝結點*/
s->Data = X;
s->Next = PtrL;
return s; /*返回新表頭指針*/
}
p = FindKth( i-1, PtrL ); /* 查找第i-1個結點 */
if ( p == NULL )
{
/* 第i-1個不存在,不能插入 */
printf("the node of i-1 is not exist!\n");
return NULL;
}
else
{
s = (List *)malloc(sizeof(List)); /*申請、填裝結點*/
s->Data = X;
s->Next = p->Next; /*新結點插入在第i-1個結點的後面*/
p->Next = s;
return PtrL;
}
}
/* 刪除第i個結點 */
List *Delete( int i, List *PtrL )
{
List *p, *s;
if ( i == 1 )
{
/* 若要刪除的是表的第一個結點 */
s = PtrL; /*s指向第1個結點*/
if (PtrL!=NULL) PtrL = PtrL->Next; /*從鏈表中刪除*/
else return NULL;
free(s); /*釋放被刪除結點 */
return PtrL;
}
p = FindKth( i-1, PtrL ); /*查找第i-1個結點*/
if ( p == NULL )
{
printf("the node of i-1 is not exist!\n"); return NULL;
}
else if ( p->Next == NULL )
{
printf("the node of i is not exist!\n"); return NULL;
}
else
{
s = p->Next; /*s指向第i個結點*/
p->Next = s->Next; /*從鏈表中刪除*/
free(s); /*釋放被刪除結點 */
return PtrL;
}
}
/* 修改元素值 */
void Change( ElementType X, int i, List *PtrL)
{
List *p;
p = FindKth( i, PtrL ); /* 查找第i個結點 */
if ( p == NULL )
{
/* 第i-1個不存在,不能插入 */
printf("the node of i-1 is not exist!\n");
return ;
}
else
{
p->Data = X;
}
}
/* 遍歷這個鏈表中的元素 */
void Traversal(List *PtrL)
{
List *p;
p = PtrL;
while(p)
{
printf("%d ", p->Data);
p = p->Next;
}
}
/* 求表長 */
int Length ( List *PtrL )
{
List *p = PtrL; /* p指向表的第一個結點*/
int j = 0;
while ( p )
{
p = p->Next;
j++; /* 當前p指向的是第 j 個結點*/
}
return j;
}
/* 程序入口 */
int main()
{
int i, index;
ElementType temp;
List *node;
List *list = NULL; /* 防止野指針 */
/* 向鏈表中插入五個元素 */
printf("Input 5 numbers : ");
for(i = 0; i < 5; i++)
{
scanf("%d", &temp);
list = Insert(temp, i + 1, list);
}
printf("************************************Traversal*****************************\n");
/* 打印鏈表中的元素 */
Traversal(list);
printf("Length = %d\n", Length(list));
printf("************************************Delete********************************\n");
/* 刪除一個元素 */
list = Delete(3, list);
Traversal(list);
printf("Length = %d\n", Length(list));
printf("************************************Insert********************************\n");
/* 插入一個元素 */
Insert(100, 2, list);
Traversal(list);
printf("Length = %d\n", Length(list));
printf("************************************Change********************************\n");
/* 插入一個元素 */
Change(888, 1, list);
Traversal(list);
printf("Length = %d\n", Length(list));
printf("************************************Find**********************************\n");
/* 查找一個元素 */
node = Find(100, list);
Traversal(list);
printf("Length = %d, Value = %d\n", Length(list), node->Data);
MakeDestroy(list); /* 銷燬這個鏈表 */
return 0;
}