數據結構鏈表總結一
最近一直在學數據結構,剛開始學習的,覺得鏈表還是比較難的,今天將自己寫的代碼貼上來
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
struct List
{
data_t data; //typedef int data_t;
struct List *pNext;
};
List *CreateList()
{
List *pHeader = NULL;
pHeader = (List *) malloc (sizeof(struct List));
if (NULL != pHeader)
{
memset(pHeader, 0, sizeof(struct List));
}
return pHeader;
}
int DestoryList(List *pList)
{
if (NULL == pList)
{
return LIST_ERROR;
}
while(pList->pNext)
{
List *p = pList->pNext;
if (NULL != p)
{
pList->pNext = p->pNext;
free(p);
p = NULL;
}
}
free(pList);
return LIST_OK;
}
int InsertList(List *pList, data_t tData, int iOffset)
{
if (NULL == pList)
{
return LIST_ERROR;
}
List *pData = (List *) malloc (sizeof(List));
if (NULL == pData)
{
return LIST_ERROR;
}
memset(pData, 0, sizeof(struct List));
pData->data = tData;
pData->pNext = NULL;
//insert
/*********************************************************************************/
if(NULL == pList->pNext)
{
pList->data = (data_t)pData; //data_t爲四字節,可以存儲四字節地址
}
/*********************************************************************************/
List *pTmp = pList;
switch(iOffset)
{
case HEADER : //在第一次插入數據的時候,尾結點的地址已保存到了頭節點
{ //後面的插入的數據不會改變尾結點的地址
pData->pNext = pList->pNext;
pList->pNext = pData;
}
break;
case TAIL :
{
/*while(pTmp->pNext) //方式1
{
pTmp = pTmp->pNext;
}
pTmp->pNext = pData;*/
/****************************************************************************************/
List *pTmp1 = (List *)pList->data; //直接通過頭結點的data域,強制轉換得到尾地址
pTmp1->pNext = pData;
pList->data = (data_t)pData;
/****************************************************************************************/
}
break;
default:
{
if (iOffset > 0)
{
while(iOffset--)
{
if (NULL == pTmp->pNext) //防止索引超出範圍
{
return LIST_ERROR;
}
pTmp = pTmp->pNext;
}
/****************************************************************************************/
if(NULL == pTmp->pNext) //索引正好指向最後一個結點,新節點成爲尾結點
{
pList->data = (data_t)pData;
}
/****************************************************************************************/
pData->pNext = pTmp->pNext;
pTmp->pNext = pData;
}
}
}
return LIST_OK;
}
int DeleteFromList(List *pList, data_t *pData, int iOffset)
{
if (NULL == pList || iOffset < 0)
{
return LIST_ERROR;
}
if (HEADER == iOffset)
{
List *pTmp = pList->pNext;
*pData = pTmp->data;
pList->pNext = pTmp->pNext;
if (NULL != pTmp)
{
free(pTmp);
}
pTmp = NULL;
/****************************************************************************/
if(NULL == pList->pNext) //刪除最後一個節點後,尾地址爲NULL
{
pList->data = 0;
}
/****************************************************************************/
return LIST_OK;
}
List *pTmp1 = pList;
if (iOffset > 0)
{
while(iOffset--)
{
if (NULL == pTmp1->pNext)
{
return LIST_ERROR;
}
pTmp1 = pTmp1->pNext;
}
List *pDel = pTmp1->pNext;
if (NULL != pDel)
{
pTmp1->pNext = pDel->pNext;
*pData = pDel->data;
free(pDel);
pDel = NULL;
if(NULL == pTmp1->pNext) //刪除的正好是最後一個結點,則更新尾結點地址
{
pList->data = (data_t)pTmp1;
}
}
else
{
return LIST_ERROR;
}
}
return LIST_OK;
}
int UpdateData(List *pList, data_t tOldData, data_t tNewData)
{
if (NULL == pList)
{
return LIST_ERROR;
}
List *pTmp = pList;
while(pTmp->pNext)
{
List *p = pTmp->pNext;
if (p->data == tOldData)
{
p->data = tNewData;
return LIST_OK;
}
pTmp = p;
}
return LIST_ERROR;
}
int SearchData(List *pList, data_t tData)
{
if (NULL == pList)
{
return LIST_ERROR;
}
List *pTmp = pList;
while(pTmp->pNext)
{
List *p = pTmp->pNext;
if (p->data == tData)
{
return LIST_OK;
}
pTmp = p;
}
return LIST_ERROR;
}
int ShowList(List *pList)
{
if (NULL == pList)
{
return LIST_ERROR;
}
List *pTmp = pList;
while(pTmp->pNext)
{
printf("%d ", pTmp->pNext->data);
pTmp = pTmp->pNext;
}
printf("\r\n");
return LIST_OK;
}
鏈表並不像數組那樣,可以由下標隨機訪問數組中的元素,他有自己的好處,他一般從堆內存中分配,而且不需要連續的存儲空間,要訪問鏈表中的結點必須通過指針去訪問,插入和刪除是鏈表操作中較複雜的操作,一般要在鏈表中插入或刪除某個元素,可以給函數傳遞一個相對鏈表第一個有效結點的偏移量,用這個偏移量來確定循環次數,如果是單向鏈表,必須要找到被刪除結點的前一個結點的位置(地址),才能正確刪除,當然如果在頭部和尾部,情況會特殊一些,進一步的,如果在尾部操作,一種方法是通過每次通過while循環找到最後一個元素的位置,當然這種做法效率並不高,可以在鏈表頭結點中保存尾結點的地址