1. 程式人生 > >線性表的單鏈表儲存學習

線性表的單鏈表儲存學習

線性表:單鏈表儲存

        單鏈表由結點構成,每個結點包括一個數據域和一個指示其直接後繼位置的指標域。連結串列中第一個結點的儲存位置叫做頭指標。在單鏈表中可以有頭結點,也可以沒有,但是一定有頭指標。一般,有頭結點的方式處理會比較簡單明瞭。以下程式是針對有頭結點的情況。頭結點的資料域可以不儲存任何資訊,頭結點的指標域儲存指向第一個結點的指標。最後一個結點的指標域指向空NULL。

/*線性錶鏈式儲存的相應程式碼:
1.線性表的順序單鏈表儲存結構程式碼
2.初始順序單鏈表
3.讀取順序單鏈表元素操作
4.插入操作
5.刪除操作
6.判斷線性表是否為空
7.順序單鏈表整表建立:頭插法
8.順序單鏈表整表建立:尾插法
9.順序單鏈表整表刪除
10.遍歷順序單鏈表
11.順序單鏈表長度
*/
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 20 /* 儲存空間初始分配量 */

typedef int Status;/* Status是函式的型別,其值是函式結果狀態程式碼,如OK等 */
typedef int ElemType;/* ElemType型別根據實際情況而定,這裡假設為int */


/* 1.線性表的順序單鏈表儲存結構程式碼 */
typedef struct Node
{
	ElemType  data;
	struct Node *next;
}Node;
typedef struct Node *LinkList;  /* 定義LinkList */

/* 2.初始順序單鏈表 */
Status InitList(LinkList *L) 
{
	 *L = (LinkList)malloc(sizeof(Node)); /* 產生頭結點,並使L指向此頭結點 */
	 if(!(*L))   /* 儲存分配失敗 */
		 return ERROR;
	 (*L)->next = NULL;  /* 指標域為空 */
	 return OK;
}

/* 3.讀取順序單鏈表元素操作 */
/* 宣告一個指標p指向連結串列的第一個結點,初始化j從1開始;
   當 j<i 時,就遍歷連結串列,讓p的指標向後移動,不斷指向下一個結點,j累加1;
   若到連結串列末端p為空,則說明第i個節點不存在;
   否則查詢成功,返回結點p的資料
*/
Status GetElem(LinkList L,int i,ElemType *e)
{
	int j;
	LinkList p;
	p = L->next; /* L是頭指標,指標p指向連結串列的第一個結點 */
	j = 1;
	while ( p && j < i)
	{
		p = p->next;
		++j;
	}
	if( !p || j>i ) /*讀取的位置為空,或者i=0 */
		return ERROR;
	*e = p->data;
	return OK;
}

/* 4.順序單鏈表插入操作 */
/* 宣告一個指標p指向連結串列的頭結點,初始化j從1開始;
   當 j<i 時,就遍歷連結串列,讓p的指標向後移動,不斷指向下一個結點,j累加1;
   若到連結串列末端p為空,則說明第i個節點不存在;
   否則查詢成功,在系統中生成一個空結點s;
   將資料元素e賦給s->data;
   單鏈表的插入標準語句s->next = p->next; p->next = s;
   返回成功。
*/

Status ListInsert(LinkList *L,int i,ElemType e)
{
	int j;
	LinkList p,s;
	p = *L;
	j = 1;
	while( p && j < i)  /*尋找第i-1個結點,不能為空 */
	{
		p = p->next;
		++j;
	}
	if( !p || j> i)
		return ERROR;
	s = (LinkList)malloc(sizeof(Node));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return OK;
}

/* 5.順序單鏈表刪除操作 */
/* 宣告一個指標p指向連結串列的頭結點,初始化j從1開始;
   當 j<i 時,就遍歷連結串列,讓p的指標向後移動,不斷指向下一個結點,j累加1;
   若到連結串列末端p為空,則說明第i個節點不存在;
   否則查詢成功,將欲刪除的結點p->next賦給q;
   單鏈表的插入標準語句p->next = q->next;
   將q結點中的資料賦值給e,作為返回;
   釋放結點q;
   返回成功。
*/

Status ListDelete(LinkList *L,int i,ElemType *e)
{
	int j;
	LinkList p,q;
	p = *L;
	j = 1;
	while( p->next && j < i) /* 尋找第i-1個結點,下一結點不能為空 */
	{
		p = p->next;
		++j;
	}
	if( !(p->next) || j> i)
		return ERROR;
	q = p->next;
	p->next = q->next;
	*e = q->data;
	free(q);
	return OK;
}

/* 6.判斷順序單鏈表釋放為空 */
Status ListEmpty(LinkList L)
{ 
    if(L->next)
            return FALSE;
    else
            return TRUE;
}
/* 7.順序單鏈表整表建立:頭插法 */
/* 宣告一個指標p和計數器變數i;
   初始化一個空連結串列L;
   讓L的頭結點的指標指向NULL,即建立一個帶頭結點的單鏈表;
   迴圈: 生成一個新結點賦值給p;
          隨機生成一個數字賦值給p的資料域p->data;
		  將p插入到頭結點與前一新結點之間p->next = (*L)->next;(*L)->next = p;;
*/
void CreateListHead(LinkList *L,int n)
{
	LinkList p;
	int i;
	srand (time (0));
	*L = (LinkList) malloc (sizeof(Node));
	(*L)->next = NULL;
	for( i = 0; i <n; i++ )
	{
		p = (LinkList)malloc(sizeof(Node));
		p->data = rand()%100 + 1; 
		p->next = (*L)->next;
		(*L)->next = p;
	}
}

/* 8.順序單鏈表整表建立:尾插法 */
/* 宣告指標p,r和計數器變數i;
   初始化一個空連結串列L,r記錄前一新結點位置;
   迴圈: 生成一個新結點賦值給p;
          隨機生成一個數字賦值給p的資料域p->data;
		  將p插入到頭結點與前一新結點之間r->next = p;r = p;;
*/
void CreateListTail(LinkList *L,int n)
{
	LinkList p,r;
	int i;
	srand (time (0));
	*L = (LinkList) malloc (sizeof(Node));
	r = *L;
	for( i = 0; i <n; i++ )
	{		
		p = (Node *) malloc (sizeof(Node));
		p->data = rand()%100 + 1; 
		r->next = p;
		r = p;
	}
	r->next = NULL; /* 表示當前連結串列結束 */
}

/* 9.順序單鏈表整表刪除:從前向後刪除 */
/* 宣告指標p,q;
   將第一個結點賦值給p;
   迴圈: 將下一結點賦值給q;釋放q;將賦值給p.
*/
Status ClearList(LinkList *L)
{
	LinkList p,q;
	p = (*L)->next;
	while( p )
	{		
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL; /* 表示當前連結串列結束 */
	return OK;
}

/* 10.遍歷順序單鏈表 */
Status ListTraverse(LinkList L)
{
    LinkList p=L->next;
    while(p)
    {
        printf("%d  ",(p->data) );
        p=p->next;
    }
    printf("\n");
    return OK;
}

/* 11.順序單鏈表長度 */
int ListLength(LinkList L)
{
    int i=0;
    LinkList p=L->next; /* p指向第一個結點 */
    while(p)                        
    {
        i++;
        p=p->next;
    }
    return i;
}


int main()
{        
    LinkList L;
    ElemType e;
    Status i;
    int j;
    i=InitList(&L);
    printf("初始化L後:ListLength(L)=%d\n\n",ListLength(L));

	for(j=1;j<=5;j++)
		i=ListInsert(&L,1,j);
    printf("在L的表頭依次插入1~5後:L.data=");
    i = ListTraverse(L); 
	printf("\n");

    printf("ListLength(L)=%d \n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n\n",i);

	i=ClearList(&L);
    printf("清空L後:ListLength(L)=%d\n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i=%d(1:是 0:否)\n\n",i);

    for(j=1;j<=10;j++)
            ListInsert(&L,j,j);
    printf("在L的表尾依次插入1~10後:L.data=");
    i = ListTraverse(L); 
	printf("\n");

	ListInsert(&L,1,0);
    printf("在L的表頭插入0後:L.data=");
    i=ListTraverse(L); 
    printf("ListLength(L)=%d \n",ListLength(L));
	printf("\n");

	GetElem(L,5,&e);
    printf("第5個元素的值為:%d\n\n",e);

	for(j=12;j>=10;j--)
    {
            i=ListDelete(&L,j,&e); /* 刪除第j個數據 */
            if(i==ERROR)
                    printf("刪除第%d個數據失敗\n",j);
            else
                    printf("刪除第%d個的元素值為:%d\n",j,e);
    }
    printf("依次輸出L的元素:");
    ListTraverse(L); 
	printf("\n");

	i=ClearList(&L);
    printf("\n清空L後:ListLength(L)=%d\n",ListLength(L));
    CreateListHead(&L,10);
    printf("整體建立L的元素(頭插法):");
    ListTraverse(L); 
	printf("\n");

    
    i=ClearList(&L);
    printf("\n刪除L後:ListLength(L)=%d\n",ListLength(L));
    CreateListTail(&L,10);
    printf("整體建立L的元素(尾插法):");
    ListTraverse(L); 
	printf("\n");

    return 0;
}