1. 程式人生 > >資料結構(c語言版)中線性表的單鏈表儲存結構

資料結構(c語言版)中線性表的單鏈表儲存結構

本文轉自:https://blog.csdn.net/prlhnxx/article/details/79174782

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
//用到的庫檔案
#include <stdio.h>	//printf() ;scanf()
#include <stdlib.h> //exit()
#include <malloc.h>	//malloc()
#include <time.h>	//srand((unsigned)time(NULL)) ;
//函式結果狀態程式碼
#define TRUE	1
#define FALSE	0
#define OK		1
#define ERROR	0
#define INFEASIBLE	-1
#define OVERFLOW	-2
//Status是函式的型別,其值是函式結果狀態程式碼
typedef int Status ;
//#define ElemType int	//也可以用巨集定義確定ElemType型別
typedef int ElemType ;
//-----線性表的單鏈表儲存結構-----
typedef struct	LNode {		//自定義資料型別
	ElemType data ;			//資料域
	struct LNode *next ;	//指標域
} LNode, *LinkList ;
 
// 操作結果:構造一個空的線性表L。
Status InitList_L(LinkList &L) {
	L = (LinkList)malloc(sizeof(LNode)) ;
	if(!L) {						//儲存分配失敗
		printf("初始化失敗") ;
		exit(OVERFLOW) ;			//exit(-1)程式異常退出
	}
	L->next = NULL ;				// 先建立一個帶頭結點的單鏈表,並使頭結點的指標域為NULL
	return OK ;
}// InitList_L
 
// 初始條件:線性表L已存在。
// 操作結果:銷燬線性表L。
Status DestroyList_L(LinkList &L) {
	free(L) ;						//釋放線性表頭結點指標域
	return OK ;
}// DestroyList_L
 
// 初始條件:線性表L已存在。
// 操作結果:將L重置為空表。
Status ClearList_L(LinkList &L) {
	LinkList p = L->next, ptmp ;	//p指向線性表頭結點
	while(p) {						//釋放每個結點的指標域
		ptmp = p->next ;
		free(p) ;
		p = ptmp ;
	}
	L->next = NULL ;				//頭結點指標域為空
	return OK ;
}// ClearList_L
 
// 初始條件:線性表L已存在。
// 操作結果:若L為空表,返回TRUE,否則返回FALSE
Status ListEmpty_L(LinkList L) {
	return L->next ? FALSE : TRUE ;
}// ListEmpty_L
 
// 初始條件:線性表L已存在。
// 操作結果:返回L中資料元素個數。
int ListLength_L(LinkList L) {
	int nElem = 0 ;
	LinkList p = L->next ;			//p指向第一個結點
	while(p) {
		nElem ++ ;
		p = p->next ;
	}
	return nElem ;
}// ListLength
 
// 初始條件:線性表L已存在,1≤i≤ListLength(L) 。
// 操作結果:用e返回L中第i個數據元素的值。
Status GetElem_L(LinkList L, int i, ElemType &e) {
	LinkList p = L->next ;			//初始化,p指向第一個結點
	int j = 1 ;						//j為計數器
	while ( p && j<i ) {			//順指標向後查詢,直到p指向第i個元素或p為空
		p = p->next ;
		++ j ;
	}
	if ( !p || j>i )
		return ERROR ;				//第i個元素不存在
	e = p->data ;					//取第i個元素
	return OK ;
}// GetElem_L 演算法2.8
 
// 初始條件:線性表L已存在,compare()是資料元素判定函式。
// 操作結果:返回L中第1個與e滿足compare()的資料元素的位序,若這樣的資料元素不存在,則返回值為0。
Status compare(ElemType listElem, ElemType e) {
	return listElem == e ? TRUE : FALSE ;
}// Compare
int LocateElem_L(LinkList L, ElemType e, Status (*pfn_compare)(ElemType, ElemType)) {
	int pos = 1 ;
	LinkList p = L->next ;			//p指向連結串列第1個元素
	while(p && !(*pfn_compare)(p->data, e)) {
		++ pos ;
		p = p->next ;				//指標後移	p->next = NULL時 意味著找到表尾元素了
	}
	if(pos<=ListLength_L(L))		//pos的值線上性表中,返回元素的位序
		return pos ;
	else
		return 0 ;
}// LocateElem_L
 
// 初始條件:線性表L已存在。
// 操作結果:若cur_e是L的資料元素,且不是第一個,則用pre_e返回它的前驅,否則操作失敗,pre_e無定義。
Status PriorElem_L(LinkList L, ElemType cur_e, ElemType &pre_e) {
	int i = LocateElem_L(L, cur_e, compare) ;
	if(i==0 || i==1) return ERROR ;
	GetElem_L(L, i-1, pre_e) ;
	return OK ;
}// PriorElem_L
 
// 初始條件:線性表L已存在。
// 操作結果:若cur_e是L的資料元素,且不是最後一個,則用next_e返回它的後繼,否則操作失敗,pre_e無定義。
Status NextElem_Sq(LinkList L, ElemType cur_e, ElemType &next_e) {
	int i = LocateElem_L(L, cur_e, compare) ;
	if(i==0 || i==ListLength_L(L)) return ERROR ;
	GetElem_L(L, i+1, next_e) ;
	return OK ;
}// NextElem_Sq
 
// 初始條件:線性表L已存在,1≤pos≤ListLength(L)+1。
// 操作結果:在L中第pos個位置之前插入新的元素e,L的長度加1。
Status ListInsert_L(LinkList &L, int pos, ElemType e) {
	LinkList p = L ;				//定義一個結構體指標變數p,指向線性表起始位置(頭結點)L。
	int j = 0 ;
	while (p && j<pos-1) {			//尋找第i-1個結點,並令p指向其前趨。
		p = p->next ;				//p非空,且j<i-1,說明指標位於線性表內
		++j ;
	}
	if (!p || j>pos-1)				//插入位置是否合法(第i個結點存在,插入的位置在表內)
		return ERROR ;
	LinkList s = (LinkList) malloc(sizeof(LNode)) ;// 生成新結點
	s->data = e ;					// 將插入的元素值賦給 新生成結點的資料域
	s->next = p->next ;				// 新生成結點的指標域 指向下一個結點 (即將結點i-1中指向第i個元素的指標域p->next,賦給新結點的指標域s->next)
	p->next = s ;					// 結點i-1的指標域 指向新生成的結點(即將指向新生成結點的指標s,賦給第i-1個元素的指標域p->next)
	printf("插入的元素:%d, 插入的位置:%d\n", e, pos) ;
	return OK ;
}// ListInsert_L 演算法2.9
 
// 初始條件:線性表L已存在且非空,1≤pos≤ListLength(L)。
// 操作結果:刪除L的第pos個數據元素,並用e返回其值,L的長度減1。
Status ListDelete_L(LinkList &L, int pos, ElemType &e) {
	LinkList p = L ;				//定義一個結構體指標變數p,指向線性表起始位置(頭結點)L。
	int j = 0 ;
	while (p->next && j<pos-1) {	//尋找第i個結點,並令p指向其前趨。
		p = p->next ;
		++j ;
	}
	if (!(p->next) || j>pos-1)		// 刪除位置是否合法(結點存在,刪除的位置在表內)
		return ERROR ;
	LinkList q = p->next ;			//使q指向i-1結點(將結點i-1中指向結點i的指標域,賦給指標變數q)
	p->next = q->next ;				//(將結點i中指向結點i+1的指標域,賦給結點i-1的指標域
	e = q->data ;					//要刪除結點的資料域,賦給e
	free(q) ;						//釋放指標變數q
	printf("刪除的元素:%d, 刪除的位置:%d\n", e, pos) ;
	return OK ;
}// ListDelete_L 演算法2.10
 
// 初始條件:線性表L已存在。
// 操作結果:依次對L的每個資料元素呼叫函式visit()。一旦vistit()失敗,剛操作失敗。
Status visit(ElemType e) {
	printf("%d ",e) ;
	return OK ;
}
Status ListTraverse_L(LinkList L, Status (*pfn_visit)(ElemType)) {
	LinkList p = L->next ;			//指標重新指向頭結點
	if(!p)	{
		printf("線性表未初始化。\n") ;
		return ERROR ;
	}
	while(p) {
		visit(p->data) ;
		p = p->next ;
	}
	printf("\n") ;
	return OK ;
}// ListTraverse
 
// 建立隨機表,包含10個隨機數(頭插法)。
Status CreateList(LinkList &L) {
	srand((unsigned)time(NULL)) ;
	//生成連結串列
	L = (LinkList)malloc(sizeof(LNode)) ;
	if(!L) {						//儲存分配失敗
		printf("初始化失敗") ;
		exit(OVERFLOW) ;			//exit(-1)程式異常退出
	}
	for (int i=0 ; i<10 ; i++) {	// 生成新結點
		LinkList p = (LinkList)malloc(sizeof(LNode)) ;
		//scanf("%d", &p->data) ;	//輸入元素值 賦給新生成結點的資料域
		p->data = rand()%100 ;
		p->next = L->next ;			//插入到表頭
		L->next = p ;
		printf("%d ", p->data) ;	// 檢視是否插入了新的元素
	}
	return OK ;
}// 個人整合
 
// 逆位序輸入(隨機產生)n個元素的值,建立帶表頭結點的單鏈線性表L(頭插法)。
void CreateList_L(LinkList &L, int n) {
	srand((unsigned)time(NULL)) ;	//初始化隨機數種子
	L = (LinkList)malloc(sizeof(LNode)) ;
	L->next = NULL ;				//先建立一個帶頭結點的單鏈表
	for (int i=n ; i>0 ; --i) {
		LinkList p = (LinkList)malloc(sizeof(LNode)) ;//生成新結點
		//scanf("%d", &p->data) ;	//輸入元素值
		//隨機生成100以內的數字
		p->data = rand()%100 ;		//將生成的元素值賦給新生成結點的資料域
        //插入到表頭
        p->next = L->next ;         //使新結點的指標域指向上一次生成的結點(將上一次生成結點的指標域賦給新結點的指標域)
        L->next = p ;               //頭結點的指標域指向新生成的結點(將指向新結點的指標p賦給頭結點的指標域)
	}
}// CreateList_L 演算法2.11
 
// 順位序輸入(隨機產生)n個元素的值,建立帶表頭結點的單鏈線性表L(尾插法)。
void CreateListTail(LinkList &L, int n) {
	srand((unsigned)time(NULL)) ;	//初始化隨機數種子
	L = (LinkList)malloc(sizeof(LNode)) ;
	L->next = NULL ;				//先建立一個帶頭結點的單鏈表
	for (int i=0 ; i<n ; ++i) {
		LinkList p = (LinkList)malloc(sizeof(LNode)) ;
		//scanf("%d", &p->data) ;	//輸入元素值
		p->data = rand()%100 ;		//隨機生成100以內的數字,將生成的元素值賦給新生成結點的資料域
		//插入到表尾
		L->next = p ;				//上一結點的指標域指向新生成的結點(將新生成結點的指標域賦給上一結點的指標的指標域)
		p->next = NULL ;			//將新結點的指標域置空
	}
}
 
// 初始化選單
void initMenu() {
	printf("\n\t\t*****************************************\n") ;
	printf("\n\t\t\t  線性表的鏈式表示和實現\n") ;
	printf("\n\t\t  1.建立隨機表\t\t  2.構造空線性表\n\t\t  3.銷燬線性表\t\t  4.清空線性表\n\t\t  5.線性表是否為空\t  6.線性表的長度") ;
	printf("\n\t\t  7.查詢表中元素\t  8.插入新元素\n\t\t  9.刪除某個元素\t 10.遍歷線性表\n\t\t 11.回到主選單\t\t  0.退出") ;
}
// 回到主選單
void mainMenu() {
	printf("\n\t\t*****************************************\n") ;
	printf("\n\t\t\t     歡迎回到主選單\n") ;
	printf("\n\t\t  1.建立隨機表\t\t  2.構造空線性表\n\t\t  3.銷燬線性表\t\t  4.清空線性表\n\t\t  5.線性表是否為空\t  6.線性表的長度") ;
	printf("\n\t\t  7.查詢表中元素\t  8.插入新元素\n\t\t  9.刪除某個元素\t 10.遍歷線性表\n\t\t 11.回到主選單\t\t  0.退出") ;
}
int main() {
	LinkList L ;
	InitList_L(L) ;
	initMenu() ;
	int select = -1 ;
	while(select != 0) {
		printf("\n請選擇你的操作:") ;
		scanf("%d", &select) ;
		switch(select) {
			case 1://建立隨機表
				printf("請輸入要建立的隨機表元素個數:\n") ;
				int nElem ;
				scanf("%d", &nElem) ;
				CreateList_L(L, nElem) ;
				printf("建立隨機連結串列:") ;
				ListTraverse_L(L, visit) ;
				break ;
			case 2://構造空線性表
				printf("構造一個空的線性表L。") ;
				InitList_L(L) ;
				ListTraverse_L(L, visit) ;
				break ;
			case 3://銷燬線性表
				if(!L) {//線性表L的頭結點存在才能銷燬
					printf("銷燬線性表L。\n") ;
					DestroyList_L(L) ;
				} else	printf("線性表未初始化。\n") ;
				break ;
			case 4://清空線性表
				printf("將L重置為空表。") ;
				ClearList_L(L) ;
				break ;
			case 5://線性表是否為空
				if (ListEmpty_L(L))
					printf("該線性表為空.\n") ;
				else
					printf("該線性表非空.\n") ;
				break ;
			case 6: { //線性表的長度
				int lLength = ListLength_L(L) ;
				printf("線性表的長度為: %d \n", lLength) ;
			}
			break ;
			case 7: { //查詢表中元素
				int nSearchOption = -1 ;
				while(nSearchOption) {
					printf("1.按位置查詢\t  2.按元素查詢\t  11.回到主選單\t  0.退出查詢\n請選擇你的操作:") ;
					scanf("%d", &nSearchOption) ;
					switch(nSearchOption) {
						case 1: { //1.按位置查詢
							printf("請輸入要查詢的位置:") ;
							int pos ;
							ElemType e ;
							scanf("%d",&pos) ;
							if(GetElem_L(L, pos, e)) {
								printf("第%d個元素的值為:%d ", pos, e) ;
								ElemType pre_e, next_e ;
								if(PriorElem_L(L, e, pre_e))
									printf("前一個元素:%d ", pre_e) ;
								else printf("前一個元素不存在 ") ;
								if(NextElem_Sq(L, e, next_e))					
									printf("後一個元素:%d \n", next_e) ;
								else printf("後一個元素不存在 \n") ;
							} else printf("請輸入正確的數字!!!\n") ;
						}
						break ;
						case 2: { //2.按元素查詢
							printf("請輸入要查詢的元素:") ;
							int pos ;
							ElemType e ;
							scanf("%d", &e) ;
							// 這裡假定隨機陣列中的元素互不重複
							pos = LocateElem_L(L, e, compare) ;
							if(pos)
								printf("值為%d是表中的第%d個元素\n", e, pos) ;
							else
								printf("沒有值為%d的元素\n", e) ;
						}
						break ;
						case 11://11.回到主選單
							mainMenu() ;
							break;
						case 0://0.退出查詢
							break;
						default:
							printf("請輸入正確的數字!!!\n");
							break ;
					}
				}
			}
			break ;
			case 8: { //插入新元素
				ElemType e ;
				int pos ;
				int nInsertOption ;
				nInsertOption = -1;
 
 
				while(nInsertOption) {
					printf("請輸入要插入的元素位置和元素的值:") ;
					scanf("%d %d", &pos, &e) ;
					if(ListInsert_L(L, pos, e)) {
						printf("插入完畢,現線上性表為:") ;
						ListTraverse_L(L, visit) ;
					} else printf("請輸入正確的數字!!!\n") ;
 
					printf("1.是  0.否  是否繼續: ") ;
					scanf("%d", &nInsertOption) ;
				}
				printf("\n") ;
			}
			break ;
			case 9: { //刪除某個元素
				int nDeleteOption ;
				nDeleteOption = -1 ;
				while(nDeleteOption) {
					printf("1.按位置查詢\t  2.按元素查詢\t  11.回到主選單\t  0.退出查詢\n請選擇你的操作:") ;
					scanf("%d", &nDeleteOption) ;
					switch(nDeleteOption) {
						case 1: { //1.按位置刪除
							ElemType e ;
							int pos ;
							printf("請輸入要刪除的位置:") ;
							scanf("%d", &pos) ;
							if(ListDelete_L(L, pos, e)) {
								printf("第%d個元素%d刪除完畢,現線上性表為:\n", pos, e) ;
								ListTraverse_L(L, visit) ;
							} else printf("請輸入正確的數字!!!\n") ;
						}
						break ;
						case 2: { //2.按元素刪除
							printf("請輸入要刪除的元素:") ;
							ElemType e ;
							int pos ;
							scanf("%d", &e) ;
							// 這裡假定隨機陣列中的元素互不重複
							pos = LocateElem_L(L, e, compare) ;
							if(pos) {
								ListDelete_L(L, pos, e) ;
								printf("第%d個元素%d刪除完結,現線上性表為:\n", pos, e) ;
								ListTraverse_L(L, visit) ;
							} else
								printf("沒有值為%d的元素\n", e) ;
						}
						break ;
						case 11://11.回到主選單
							mainMenu() ;
							break;
						case 0://0.退出查詢
							break;
						default:
							printf("請輸入正確的數字!!!\n");
							break ;
					}
				}
			}
			break ;
			case 10://遍歷線性表
				printf("遍歷線性表:") ;
				ListTraverse_L(L, visit) ;
				break ;
			case 11://回到主選單
				mainMenu() ;
				break ;
			case 0://退出
				break ;
			default:
				printf("請輸入正確的數字!!!\n") ;
				break ;
		}
	}
	return 0 ;
}